OAuth 2.0 & OpenID Connect
How to integrate Vaultaris as an authorization server — authorization code, client credentials, password flows, DPoP sender-constrained tokens, and hosted login.
Vaultaris implements RFC 6749 (OAuth 2.0), OpenID Connect Core 1.0, and RFC 9449 (DPoP). OIDC discovery document at GET /.well-known/openid-configuration. JWK set at GET /.well-known/jwks.json.
Supported grant types
| Grant | Use case |
|---|---|
| Authorization code + PKCE | Web apps, mobile apps, SPAs (recommended) |
| Client credentials | Server-to-server (machine auth) |
| Password (ROPC) | Legacy integrations, CLIs, trusted first-party apps |
| Refresh token | Obtaining new access tokens without re-authentication |
Authorization code flow (recommended)
Step 1 — Redirect user to /oauth/authorize
GET /oauth/authorize
?response_type=code
&client_id={client_id}
&redirect_uri={uri}
&scope=openid profile email
&state={random_state}
&code_challenge={S256_challenge}
&code_challenge_method=S256
PKCE is mandatory for public clients (client_type=public). Generate a 43–128 character random code_verifier; the code_challenge is its SHA-256 base64url encoding.
Step 2 — Consent
Vaultaris redirects the user to {EXTERNAL_URL}/consent/{request_id}. Retrieve details: GET /oauth/consent/{request_id}. Approve: POST /oauth/consent/{request_id}/approve with { "approved_scopes": ["openid","profile"] }. Deny: POST /oauth/consent/{request_id}/deny.
Step 3 — Exchange code for tokens
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code={code}
&redirect_uri={uri}
&client_id={client_id}
&client_secret={client_secret} # confidential clients only
&code_verifier={verifier} # public clients
Response:
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJ...",
"id_token": "eyJ...",
"scope": "openid profile email"
}
Client credentials flow
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id={client_id}
&client_secret={client_secret}
&scope=api:read
Refresh token flow
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token={token}
&client_id={client_id}
&client_secret={client_secret}
Token introspection
POST /oauth/introspect (form-encoded token, token_type_hint, client credentials). Returns { active, sub, client_id, scope, exp, tenant_id }.
Token revocation
POST /oauth/revoke (form-encoded token, token_type_hint, client credentials).
UserInfo endpoint
GET /oauth/userinfo with Authorization: Bearer {access_token}. Returns sub, email, email_verified, name, preferred_username, and other claims based on granted scopes.
Scopes
| Scope | Claims included |
|---|---|
openid | sub, iss, aud, exp, iat |
profile | name, given_name, family_name, preferred_username, locale, zoneinfo |
email | email, email_verified |
phone | phone_number, phone_number_verified |
DPoP — Sender-Constrained Tokens (RFC 9449)
DPoP binds an access token to a specific client key pair, making stolen tokens useless without the private key.
How it works
- The client generates an asymmetric key pair (ed25519 or P-256) at startup and retains the private key.
- On every token request, the client sends a
DPoPheader containing a signed JWT (dpop_proof) that includes:jwk— the public keyhtm/htu— HTTP method and URLiat/jti— timestamp and unique nonce
- Vaultaris binds the issued token to the public key's thumbprint (
cnf.jktclaim). - On every resource request, the client presents both the access token and a fresh
DPoPproof. Vaultaris verifies the proof signature and rejects requests where the key doesn't match.
SDK support
The Vaultaris Rust and Node.js SDKs include transparent DPoP support — pass a DpopSigner when constructing the client and the SDK handles proof generation automatically. Browser apps can use the sdk-web package which implements DPoP via the Web Crypto API.
Manual integration
Add the DPoP header to the token endpoint request:
POST /oauth/token
DPoP: eyJhbGciOiJFZERTQSIsInR5cCI6ImRwb3Arand0IiwiandrIjp7ImNydiI6IkVkMjU1MTkiLCJ4IjoiLi4uIn19.eyJqdGkiOiJ1bmlxdWUiLCJodG0iOiJQT1NUIiwiaHR1IjoiaHR0cHM6Ly9hdXRoLmV4YW1wbGUuY29tL29hdXRoL3Rva2VuIiwiaWF0IjoxNzE2MDAwMDAwfQ.{signature}
Subsequent API calls require a fresh DPoP proof for each request (different jti and iat).
Hosted Login
Vaultaris provides a white-label login page for each tenant at /hosted/{tenant_slug}/login. This page is configurable with tenant branding (logo, colors, custom CSS).
Config endpoint
GET /api/v1/hosted/{tenant_slug}/config — returns tenant branding, enabled auth methods, IdP list, MFA settings, and default_client_id.
Supported methods in hosted login
- Username + password
- TOTP MFA (via
/api/v1/hosted/{slug}/mfa/verify) - MFA backup codes
- Federated IdP buttons (OAuth/OIDC providers)
After successful auth, the token is delivered in the URL hash (never the query string — the hash is never sent to the server):
/hosted/{slug}/login#access_token={token}&token_type=Bearer&return_to={url}
Cross-domain SSO (Global Sessions)
When a user belongs to a group with global_session_enabled = true, the token response includes a global_session_token.
{
"access_token": "...",
"global_session_token": "gst_64randombytes..."
}
To transfer the session to a different domain:
POST /api/v1/sessions/global/{token}/transferwith{ "target_domain": "app2.example.com" }→ returns a one-timetransfer_token(60-second lifetime).- On the target domain:
POST /api/v1/sessions/transfer/redeemwith{ "token": "...", "domain": "app2.example.com" }→ returns theGlobalSessionobject.
Validate an existing session: GET /api/v1/sessions/global/{token}?domain=app2.example.com&require_mfa=false.
Registering an OAuth client
POST /api/v1/tenants/{tenant_id}/clients
{
"name": "My App",
"client_type": "public",
"redirect_uris": ["https://app.example.com/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"allowed_scopes": ["openid", "profile", "email"],
"pkce_required": true,
"consent_required": false
}
The response includes client_id and client_secret (shown once only for confidential clients).