Authentication
The application authentication contract and provider interface.
Goalkeeper exposes one provider-neutral authentication contract to the browser.
The REST API owns the canonical routes and user shape while an injected
AuthBackend owns the provider-specific session lifecycle.
Browser contract
| Route | Purpose |
|---|---|
GET /v1/auth/config | Return the configured browser authentication method |
GET /v1/auth/session | Return the canonical user and organization context |
GET /v1/auth/login | Begin login and continue to a same-origin URL |
POST /v1/auth/login | Sign in with the built-in email provider |
POST /v1/auth/register | Register an email principal |
POST /v1/auth/verify-email | Consume an email verification token after browser confirmation |
GET /v1/auth/callback | Complete login and continue to the application |
POST /v1/auth/logout | End the session and return the next browser URL |
An authenticated session contains the provider-neutral application identity and organization context required by the web client:
{
"user": {
"id": "user-id",
"displayName": "Example User",
"email": "user@example.com"
},
"activeOrganizationId": "organization-id",
"organizations": [
{
"id": "organization-id",
"name": "Example User",
"role": "owner"
}
]
}The web application does not depend on provider-specific claims, tokens, or SDK types. Application-owned organization data is resolved after the authentication provider returns the canonical user, so custom providers do not need to manage Goalkeeper memberships.
Provider interface
Self-hosted operators can supply an AuthBackend to createApiHandler. The
provider is responsible for initiating login, validating callbacks, resolving
its authenticated principal to the canonical application user, issuing and
revoking the session cookie, and coordinating logout.
This keeps authentication mechanisms behind a provider interface. Replacing the provider does not change the browser routes, the protected page, or the application user model.
If a provider accepts JWT access tokens, it validates their signature,
algorithm, key ID, issuer, audience, and expiry before constructing an
AuthSession. JWT key rotation and issuer-specific claims stay inside the
provider.
Managed trusted-proxy provider
The standalone API includes a vendor-neutral redirect provider for managed
deployments. Select it with AUTH_PROVIDER=trusted_proxy and configure:
AUTH_PROXY_SECRET=<at-least-32-byte-shared-secret>
AUTH_PROXY_ISSUER=managed-deployment-identifier
AUTH_PROXY_AUDIENCE=goalkeeper-environment-identifier
AUTH_PROXY_LOGIN_URL=https://example.com/_auth/login
AUTH_PROXY_LOGOUT_URL=https://example.com/_auth/logoutThe proxy authenticates the provider session and injects two private-hop
headers: a base64url JSON assertion in x-goalkeeper-auth-assertion and its
HMAC-SHA-256 signature in x-goalkeeper-auth-signature. The assertion version
is 1 and contains iss, aud, Unix iat, the exact uppercase request
method, exact path plus query in path, sessionId, and the canonical
user fields.
The backend accepts assertions for at most 30 seconds, permits no more than five seconds of future clock skew, verifies the signature before returning a session, and binds the assertion to the exact request method and path. The proxy must strip both headers from every client request before signing its own values. The API must not be directly reachable around that proxy, and the shared secret must be unique to the deployment.
Provider SDKs, access tokens, refresh tokens, and cookies remain in the managed proxy. Goalkeeper persists only its own organization and product data keyed by the canonical provider-qualified user ID.
Built-in email provider
The default self-hosted configuration uses the built-in email provider. Principals, Argon2id password hashes, opaque session hashes, and email-verification token hashes are stored in PostgreSQL. Verification tokens are single-use and expire after 24 hours. Login uses one invalid-credentials response for unknown, incorrect, and unverified accounts.
Verification links open the web application's /verify-email page with the
token in the URL fragment. The page removes the fragment from browser history
and requires explicit confirmation before it sends the token to the API. This
prevents automated link scanners from consuming verification tokens.
The local email-delivery adapter logs the verification message and link to the API terminal. It is disabled in production. To verify a local principal without opening and confirming the link, run:
bun run auth:verify-email -- user@example.comOpen /home to exercise the protected application. Unauthenticated requests are
sent to /sign-in; logout from the sidebar account menu revokes the persisted
session and returns there. /account remains a compatibility redirect to the
Profile settings page.
API Token settings at /settings/api-tokens provide
API token management. See
Organizations for bootstrap and switching.