Auth Service treats its PostgreSQL schema as a first-class versioned artifact. Flyway owns every DDL change: tables, indexes, extensions, and constraints are all defined in versioned SQL migration files. Hibernate is configured withDocumentation 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.
spring.jpa.hibernate.ddl-auto=validate — it reads the existing schema at startup and verifies that the database structure matches the JPA entity mappings, but it never creates, alters, or drops anything. This separation of concerns (AD-7) means the schema is always traceable through source control and the exact same SQL runs in every environment, from a developer’s laptop to production.
Migration History
The migration files live insrc/main/resources/db/migration/ and are applied in version order by Flyway on every startup.
V1__init.sql — Extensions
Enables thepgcrypto PostgreSQL extension, which provides the gen_random_uuid() function used by JPA entities to generate UUID primary keys server-side.
V2__accounts.sql — Core Account Schema
Introduces the three tables that form the foundation of the identity model:accounts, account_roles, and verification_tokens.
V3__refresh_tokens.sql — Refresh Token Family Tracking
Adds therefresh_tokens table, which tracks the full lifecycle of every issued refresh token. The family_id column groups tokens that share a rotation lineage — if a token from a family is presented after it has already been used, the entire family is revoked to prevent replay attacks. Two indexes accelerate the most common lookups (by family and by account).
V4__federated_identities.sql — OAuth2 Provider Links
Adds thefederated_identities table, which links an Auth Service account to one or more external OAuth2 provider identities (currently Google and GitHub). The (provider, provider_user_id) unique constraint prevents the same external identity from being attached to multiple accounts.
Key Schema Design Choices
UUID primary keys viapgcrypto
All tables use uuid as the primary key type. UUIDs are generated in application code (JPA entities) using gen_random_uuid() from the pgcrypto extension enabled in V1. This avoids sequential integer IDs that leak record counts and simplifies distributed ID generation.
Hashed tokens, never plaintext
The token_hash column in both verification_tokens and refresh_tokens stores a secure hash of the actual token value, never the raw token. This means a database breach does not expose usable tokens. The same principle applies to password_hash in accounts.
status as a text enum
The accounts.status column uses text NOT NULL rather than a PostgreSQL ENUM type. This keeps DDL migrations simpler — adding a new status value (e.g. LOCKED) is a no-op at the database level and only requires updating the application domain model.
All timestamps as timestamptz
Every timestamp column uses timestamptz (timestamp with time zone) rather than timestamp. PostgreSQL stores timestamptz values in UTC internally and converts to the session time zone on read, making the schema unambiguous across deployments in different time zones.
Nullable lifecycle columns
Columns like used_at, revoked_at, consumed_at, and locked_until are nullable by design — NULL means the event has not yet occurred. A non-null value records precisely when it did.
Adding a New Migration
Create a new versioned SQL file
Place the file in The version must be strictly greater than the highest existing version. Descriptions use underscores as word separators. For example, to add a sessions table after V4:
src/main/resources/db/migration/ following the Flyway naming convention:Write your SQL
Write plain, idiomatic PostgreSQL DDL. Reference existing tables with foreign keys where appropriate:
Update the corresponding JPA entity
After Flyway applies the migration and creates the table, update or create the matching JPA entity so that Hibernate’s schema validation (
ddl-auto=validate) passes. If the entity and the table structure do not match, the application will refuse to start.Verify locally
Start the service locally (see Local Setup). Flyway logs each applied migration:If there is a checksum mismatch or a version conflict, Flyway will throw
FlywayException at startup with a descriptive message.Auth Service sets
spring.jpa.hibernate.ddl-auto=validate in application.properties. On every startup, Hibernate compares the live database schema against the JPA entity mappings. If a table, column, or constraint that an entity expects is absent — for example, because a migration was skipped or rolled back — the application throws a SchemaManagementException and exits. This acts as an automatic consistency check between your migration files and your entity code.