Same token, a different door
In lesson 8a we built the session-token contract: the server issues one JWT, the client stores and sends it. Google sign-in doesn't create a new contract — it just adds another way to obtain that same token.
Compare the two paths:
Email (8a): email+password ─▶ POST /login ─▶ our JWT
Google (8b): Google ID token ─▶ POST /auth/google ─▶ our JWT (the same one!)
From there on, the app can't tell the difference — SecureTokenStorage, AuthInterceptor, orders (lesson 9) all work identically no matter how you signed in. That's the heart of this lesson: same token, a different door.
The full Google flow:
1. App: Credential Manager shows the Google account picker
2. User picks an account → Google returns an "ID token" (a signed JWT)
3. App sends the ID token → POST /auth/google
4. Server verifies it with Google (signature, aud, exp) → idtoken.Validate
5. Server finds/creates the user → issues OUR session JWT
6. App stores that JWT — exactly like 8a
The Google ID token ≠ our session token. The Google token only proves "Google confirms this is user X." We trust it only after verifying on the server, and then we issue our own token. The client never talks to our DB directly with a Google token.
Console setup (Google Cloud Console). Before writing code you need two OAuth clients:
- Android client — tied to your app's package name (
eif.viko.lt.pica) and your debug SHA-1 signature. It's what lets the phone obtain a Google token at all. - Web client — its ID is used by BOTH the app (
setServerClientId) AND the server (as theaudit checks). This is the source of the most common gotcha, which we'll cover.
Verify-docs. We use Credential Manager (
androidx.credentials+ "Sign in with Google") — the current API. The oldGoogleSignInClientis deprecated — don't author against it.