Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ricardomb-tech/auth-service/llms.txt

Use this file to discover all available pages before exploring further.

Auth Service is designed to be production-ready from the start, but several configuration steps must be completed before it is safe to expose publicly. The prod Spring profile has no default values for any environment variable — this is intentional. Every secret, credential, and connection string must be supplied explicitly through the environment, so a misconfigured deployment fails loudly at startup rather than silently running with insecure placeholders.
The prod profile (application-prod.properties) contains no default values. If any required variable listed below is missing or empty, the application will fail to start. This is a deliberate fail-fast design decision (AD-10) — a partial configuration is worse than no configuration.

Required Environment Variables

All of the following variables must be set in the environment before starting Auth Service with the prod profile. There are no fallbacks.
VariableDescription
DB_HOSTHostname or IP address of the PostgreSQL 15 server.
DB_PORTPostgreSQL port (typically 5432).
DB_NAMEName of the database (e.g. auth_service).
DB_USERPostgreSQL user with read/write access to DB_NAME.
DB_PASSWORDPassword for DB_USER.
JWT_SECRET_CURRENTActive HS256 signing secret. Must be ≥ 256 bits (32+ random bytes, base64-encoded).
JWT_SECRET_PREVIOUSPrevious signing secret kept during rotation. Set to empty string when not rotating.
GOOGLE_CLIENT_IDOAuth2 client ID from Google Cloud Console.
GOOGLE_CLIENT_SECRETOAuth2 client secret from Google Cloud Console.
GITHUB_CLIENT_IDOAuth2 client ID from GitHub Developer Settings.
GITHUB_CLIENT_SECRETOAuth2 client secret from GitHub Developer Settings.
OAUTH2_SUCCESS_REDIRECT_URIFrontend URI to redirect to after a successful OAuth2 login (e.g. https://app.example.com/oauth2/success).
OAUTH2_FAILURE_REDIRECT_URIFrontend URI to redirect to after a failed OAuth2 login (e.g. https://app.example.com/oauth2/failure).
MAIL_HOSTSMTP server hostname for transactional email.
MAIL_PORTSMTP server port (e.g. 587 for STARTTLS, 465 for SMTPS).
KAFKA_BOOTSTRAP_SERVERSComma-separated list of Redpanda/Kafka broker addresses (e.g. broker1:9092,broker2:9092).
AUTH_ADMIN_EMAILEmail address for the initial admin account (FR-12). Required at startup to seed the first administrator.
AUTH_ADMIN_PASSWORDPassword for the initial admin account. Must meet the application’s password-strength requirements.
APP_BASE_URLPublic base URL of the Auth Service (e.g. https://auth.example.com). Used to construct verification and password-reset links in emails.
Do not point MAIL_HOST and MAIL_PORT at a MailHog instance in production. MailHog silently discards all email and is intended only for local development. Use a real SMTP provider (Amazon SES, Postmark, SendGrid, etc.) with proper authentication credentials.

Security Checklist

1

Generate a strong JWT signing secret

The JWT access tokens are signed with HS256. The secret must be at least 256 bits (32 bytes) of cryptographically random data.
openssl rand -base64 32
Set the output as JWT_SECRET_CURRENT. Store it in your secrets manager (AWS Secrets Manager, HashiCorp Vault, Kubernetes Secrets, etc.) — never commit it to source control or bake it into a container image.
2

Configure production SMTP credentials

Replace the MailHog dev values with real SMTP server details. Depending on your provider, you will also need to set MAIL_USERNAME and MAIL_PASSWORD (or equivalent authentication properties) in your environment or Spring configuration overlay.
MAIL_HOST=smtp.your-provider.com
MAIL_PORT=587
3

Register production OAuth2 callback URLs

In the Google Cloud Console and GitHub Developer Settings, add the production callback URL for each provider before setting the client credentials:
  • Google: https://auth.example.com/login/oauth2/code/google
  • GitHub: https://auth.example.com/login/oauth2/code/github
Then set all four OAuth2 variables (GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET) and update the redirect URIs:
OAUTH2_SUCCESS_REDIRECT_URI=https://app.example.com/oauth2/success
OAUTH2_FAILURE_REDIRECT_URI=https://app.example.com/oauth2/failure
4

Ensure PostgreSQL is network-isolated

The database should not be reachable from the public internet. Place it in a private subnet or VPC, and restrict access to only the Auth Service’s network identity (security group, firewall rule, or equivalent). Verify DB_HOST resolves to a private address.
5

Start the service with the prod profile

./mvnw spring-boot:run -Dspring-boot.run.profiles=prod
Or, if running a packaged JAR:
java -Dspring.profiles.active=prod -jar auth-service-0.0.1-SNAPSHOT.jar
Watch the startup logs. Flyway will log each applied or already-applied migration. If any required environment variable is missing, the application will throw a BeanCreationException or IllegalStateException and exit immediately — check the log for the variable name.

Zero-Downtime JWT Secret Rotation

Auth Service supports rotating the HS256 signing secret without invalidating in-flight access tokens, using a two-slot secret pair: JWT_SECRET_CURRENT and JWT_SECRET_PREVIOUS. The verification logic tries JWT_SECRET_CURRENT first and falls back to JWT_SECRET_PREVIOUS if validation fails. This means tokens signed with either secret are accepted during the rotation window. Rotation procedure:
  1. Before rotation: JWT_SECRET_CURRENT holds the active secret; JWT_SECRET_PREVIOUS is empty or holds an older key.
  2. Introduce the new secret: Set JWT_SECRET_PREVIOUS to the current value of JWT_SECRET_CURRENT, and set JWT_SECRET_CURRENT to a newly generated secret (openssl rand -base64 32).
  3. Redeploy the service with the updated environment. New tokens are immediately signed with the new JWT_SECRET_CURRENT; tokens already issued with the old secret are still validated via JWT_SECRET_PREVIOUS.
  4. Wait for old tokens to expire: Access tokens have a 15-minute TTL (auth.jwt.access-ttl=15m). After 15 minutes, no valid in-flight token can still be signed with the old secret.
  5. Clear the previous secret: Set JWT_SECRET_PREVIOUS to an empty string and redeploy. Rotation is complete.
# Step 2 — deploy with both secrets present
JWT_SECRET_CURRENT=<new-secret>
JWT_SECRET_PREVIOUS=<old-secret>

# Step 5 — after old tokens expire, remove the previous secret
JWT_SECRET_CURRENT=<new-secret>
JWT_SECRET_PREVIOUS=

Health Checks

Auth Service includes Spring Boot Actuator (spring-boot-starter-actuator) for operational observability, but the management endpoints are not exposed publicly by default:
management.endpoints.web.exposure.include=none
For Kubernetes liveness and readiness probes, configure a dedicated management port (planned for Epic 5) and expose only the health endpoint on that port. Until then, you can perform a TCP check against port 8080 or temporarily expose the health group on a firewall-restricted management port by setting:
management.server.port=8081
management.endpoints.web.exposure.include=health
management.endpoint.health.probes.enabled=true
This keeps the operational endpoint off the public-facing port while still giving your container orchestrator a proper liveness/readiness signal.

Build docs developers (and LLMs) love