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.