Authentication
The Swappr API uses RS256 JWTs for access tokens and opaque rotating refresh tokens for long-lived sessions. We do not use cookies; clients hold tokens and send them on every request.Access tokens
- Algorithm: RS256 (asymmetric). The public key is distributed safely; only Swappr’s API can sign.
- TTL: 15 minutes.
- Header:
Authorization: Bearer <accessToken>. - Claims:
401 UNAUTHENTICATED. Call /auth/refresh to mint a new one.
Refresh tokens
- Format: 256-bit random, base64url encoded (43 chars). Opaque to clients.
- Storage at rest: argon2id hash; the raw value is shown to the client ONCE on issue and never again.
- TTL: 30 days.
- Rotation: every
/auth/refreshcall returns a new refresh token and invalidates the old one. Re-using a refresh token is treated as theft — the entire session chain is revoked and the API returns401 TOKEN_REVOKED.
Socket tickets
Socket.IO handshakes don’t carry anAuthorization header well, and putting a JWT in a query string leaks it into access logs. So:
- The authenticated client calls
POST /api/v1/auth/socket-ticket(REST). - The API issues a one-shot 60-second ticket and stores it in Redis.
- The client connects to the WebSocket with
?ticket=<ticket>in the handshake URL. - The realtime server atomically GETDELs the ticket from Redis — exactly one socket admission per ticket, no replay.
Logout
POST /auth/logout— revokes the current session’s refresh token. Other devices stay logged in.POST /auth/logout-all— revokes every refresh token for this user. All devices are kicked.
Sign in with Google
Swappr uses the Firebase ID-token flow (not a server-side redirect). The mobile app performs native Google sign-in through the Firebase Auth SDK, obtains a Firebase ID token, and POSTs it toPOST /auth/oauth/google. The backend verifies the token with firebase-admin (signature, expiry, issuer, and audience = our Firebase project), finds-or-creates the user, and issues the same access/refresh pair as the email path.
- First-time Google users are created on the fly (
201,isNewUser: true) and flow into the normal onboarding state machine. - Returning users get
200withisNewUser: false. - An email already owned by a non-Google account is rejected with
409 ACCOUNT_EXISTS_VIA_OAUTH— Swappr never silently links Google to a pre-existing account.
/auth/oauth/apple.