Skip to main content

Auth, OTP, and token rotation

Auth-service is the only issuer. A successful password, OTP, or OAuth login creates a refresh-token row and returns a short-lived access JWT. RefreshTokenUseCase rotates: the presented refresh token is marked used and a new one is stored. Presenting a used token revokes the family. That closes replay after theft, at the cost of logging out every session in the family.

OTP​

otp_challenges stores the challenge, not a log of the code. Delivery goes through OtpSenderPort to communication-service (AUTH_COMMUNICATION_SERVICE_URL). Email OTP and phone OTP paths are both rate-limited at Kong. OtpChallengeCleanupJob deletes expired rows so the table does not grow without a bound.

Local Spring events (UserLoggedInEvent, UserLoggedOutEvent) stay in-process. They are not integration events. Downstream services learn about users only from outbox facts: registered, profile updated, welcome email, deleted.

OAuth​

Google and Apple sign-in verify ID tokens against the configured client ids (AUTH_GOOGLE_*, AUTH_APPLE_IOS_BUNDLE_ID). The client secret and the JWT private key stay in the secret store. Docs and tickets name the variable only.

Account closure​

Deletion is a two-step request plus confirmation, with an impact query that calls feed. After commit, auth.user-deleted lets social, feed, expense, and messaging drop or anonymize projections. Auth then anonymizes names and purges deactivated accounts on a schedule. Do not delete the user row in another schema to "help".

What to test when you touch this​

Refresh reuse, OTP expiry, and the outbox row existing in the same transaction as the user insert. Unit coverage lives next to the use cases; this module does not boot Testcontainers.