Code

The auth layer — PicaApi, TokenStorage, AuthRepository

Four files in the code column as tabs, in the order they depend on each other: PicaApi.ktTokenStorage.ktSecureTokenStorage.ktAuthRepository.kt.

1. PicaApi.kt (modify) — the lesson-5 interface grows: it gains the register and login endpoints plus the AuthRequest/AuthResponse bodies. The diff shows only the new lines; the menu endpoint stays exactly as it was.

@POST("login")
suspend fun login(@Body request: AuthRequest): AuthResponse

@Serializable data class AuthResponse(val token: String)   // ← the contract: server returns a token

2. TokenStorage.kt (create) — the storage contract (how we store a token, decoupled from where). AuthRepository depends on this interface, not on the encrypted class.

3. SecureTokenStorage.kt (create) — the encrypted implementation (DataStore + Google Tink AEAD). The point isn't Tink itself — it's that the token on disk is encrypted, and hasValidToken() checks validity by reading the JWT's exp field. The full file is in the tab; the crypto is boilerplate you can reuse.

4. AuthRepository.kt (create) — short, because the contract does all the work: login()/register() call the server and save the returned token. isLoggedIn() just checks whether the store holds a valid token.

Tip. AuthResponse(val token: String) is the entire result of "logging in." No passwords, no user object: one token. The less you keep on the phone, the less you can lose.