← All three datastores

Auth datastore

Identity only — users, provider links, sessions and passkeys. No passwords exist in this schema and none ever will.

govdeets_auth · AUTH_DATABASE_URL · prisma/auth/schema.prisma

GovDEETS — Auth datastore

Generated by prisma-markdown

Identity

User

A person. The only personally identifying data we hold is what the identity provider hands us at sign-in.

Properties as follows:

  • id:
  • email:
  • emailVerified:
  • displayName:
  • avatarUrl:
  • status:
  • isMock

    Set only for users created by the local mock providers, so a production deployment can refuse to authenticate them even if this row travels.

  • createdAt:
  • updatedAt:
  • lastLoginAt:

Identity

A link between a User and an external identity provider. One user can hold several — signing in with Google and later with Azure attaches a second Identity to the same User when the provider-verified email matches.

Access and refresh tokens are deliberately absent. We authenticate against these providers; we do not act on the user's behalf at them. When an integration genuinely needs a token (Slack, Jira), that token belongs to an Integration in core, scoped to an organization — not to a person's login.

Properties as follows:

  • id:
  • userId:
  • provider

    google, azure, amazon, github, tiktok, … and the same names again in local development, served by the mock provider set.

  • providerUserId: The provider's own stable subject identifier for this user.
  • providerEmail:
  • isMock:
  • createdAt:
  • lastUsedAt:

WebAuthnCredential

A registered passkey. publicKey is public by definition, so storing it is safe; the private half never leaves the user's authenticator.

Properties as follows:

  • id:
  • userId:
  • credentialId: Base64url-encoded credential ID as returned by the authenticator.
  • publicKey:
  • signCount

    Replay defence: must strictly increase across authentications, for authenticators that implement a counter at all.

  • transports:
  • deviceType

    singleDevice or multiDevice. A multi-device credential is synced through a platform keychain and survives losing the device.

  • backedUp:
  • aaguid:
  • nickname: User-supplied label, so someone with four passkeys can revoke the right one.
  • createdAt:
  • lastUsedAt:

Sessions

Session

A logged-in session. The cookie the browser holds is a random 256-bit token; only its SHA-256 hash is stored here, so read access to this table cannot be used to impersonate anyone.

Properties as follows:

  • id:
  • userId:
  • tokenHash:
  • expiresAt:
  • createdAt:
  • lastSeenAt:
  • revokedAt:
  • ip:
  • userAgent:
  • activeOrganizationId

    Which organization this session is currently acting in — an opaque pointer into the core datastore's Organization. No foreign key, by design.

AuthChallenge

Short-lived server-side state for flows that span two requests: the OAuth authorization round trip (state + PKCE verifier) and the WebAuthn registration/authentication challenge.

Properties as follows:

  • id:
  • kind:
  • userId:
  • value: The WebAuthn challenge, or the OAuth state parameter.
  • codeVerifier: PKCE code verifier. OAuth flows only.
  • provider:
  • redirectTo: Where to send the user once the flow completes.
  • expiresAt:
  • consumedAt:
  • createdAt:

Audit

AuthEvent

Security audit trail. Kept in the auth database rather than alongside the application audit log, so "who tried to get in" survives independently of the business data — and so shipping business data to an analyst never ships the authentication history with it.

Properties as follows:

  • id:
  • userId:
  • kind

    signin.start, signin.success, signin.failure, session.revoke, passkey.register, passkey.remove, …

  • provider:
  • success:
  • reason: Failure reason, safe to show an administrator.
  • ip:
  • userAgent:
  • createdAt: