Authaz logoAuthaz
DocumentationAPI Reference
  • Get Started

    • Authaz
    • Core Concepts
    • Set up your app
    • Quickstart — cURL
  • Authentication

    • Authentication Settings
    • Signup
    • Invitations
    • Password Authentication
    • Multi-Factor Auth
    • Magic Link
    • OAuth / Social Login
    • Passkey (WebAuthn)
    • SAML SSO
    • Machine-to-Machine (M2M)
    • API Keys
  • Authorization

    • Authorization
    • Resources
    • Policies
    • Roles
    • Access Explorer
  • Tenancy

    • Multi-tenancy
    • Tenancy Customization
  • Brand & Host

    • Branding
    • Custom Domains
    • Communications & Email Templates
  • Operate

    • Users
    • Analytics
    • Audit Logs
    • Application Settings
  • SDK Quickstarts

    • Quickstart — Next.js
    • Quickstart — React SPA
    • Quickstart — Hono
    • Quickstart — .NET (Authaz.Sdk)
  • Recipes

    • Recipes & Cookbook
    • Next.js — first integration
    • Next.js — B2B SaaS (multi-tenant)
    • Hono — first integration
    • Hono — B2B SaaS (multi-tenant)
    • React SPA — first integration
    • React SPA — B2B SaaS (multi-tenant)
    • .NET — first integration
    • .NET — B2B SaaS (multi-tenant)
  • Reference

    • Tokens
    • API Reference
    • Errors & Troubleshooting
  • Documentation

    • How Authaz is Built
  1. Authaz
  2. Docs
  3. Authentication
  4. Authentication Settings

Authentication

Authentication Settings

5 min read·Updated Jun 19, 2026

The Settings card under Application → Authentication is the OAuth 2.0 / Authaz Sign-In configuration surface. It's where you tell Authaz: which URLs your app will be redirected to, what scopes it can request, how long tokens live, and how sessions behave. Most production issues — redirect_uri_mismatch, expired-token loops, "user keeps getting logged out" — trace back to this page.

curl -X PUT https://your-app.authaz.io/api/v1/applications/{appId}/universal-login \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "redirectUris": [
      "https://yourapp.com/auth/callback",
      "http://localhost:3000/auth/callback"
    ],
    "postLogoutRedirectUris": [
      "https://yourapp.com",
      "http://localhost:3000"
    ],
    "allowedScopes": ["openid", "profile", "email", "offline_access"],
    "requireTenantHint": false,
    "accessTokenLifetime": 3600,
    "refreshTokenLifetime": 2592000,
    "authorizationCodeLifetime": 600,
    "sessionTimeoutMinutes": 480,


Previous
Quickstart — cURL
Next
Signup
"rememberMeTimeoutMinutes": 43200,
"applicationCredentialId": "cred_01h..."
}'

Where it lives#

Dashboard → Application → Authentication → Settings.

Redirect URIs#

redirectUris is the allow-list of URLs Authaz will redirect users back to after authentication. Every URL your app uses must be listed here.

{
  "redirectUris": [
    "https://yourapp.com/auth/callback",
    "https://staging.yourapp.com/auth/callback",
    "http://localhost:3000/auth/callback"
  ]
}

Rules Authaz enforces (per OAuth 2.0):

  • Exact match. https://yourapp.com/callback does not match https://yourapp.com/callback/. Trailing slashes matter.
  • Scheme matters. https and http are different. Production should be https only; localhost is the standard exception.
  • No wildcards in production. https://*.yourapp.com/callback is not valid. Add each subdomain explicitly. (Localhost can use any port — http://localhost:* is treated as a special case.)
  • Query strings are stripped before matching. ?utm=... on the way out is fine.

A mismatch returns error=invalid_request, error_description=redirect_uri_mismatch and the user never reaches your callback. The audit log records every mismatch so you can see exactly what was attempted.

postLogoutRedirectUris is the same allow-list but for the logout flow — where users land after POST /oauth2/logout. Same matching rules.

Allowed scopes#

allowedScopes is the menu of OAuth scopes your application is allowed to request. Authaz rejects any token request whose scope parameter contains a value not on this list.

Default: ["openid", "profile", "email"]. Standard OIDC scopes plus any custom scopes you've defined for resources.

ScopeWhat it grants in the access token
openidRequired for OIDC. Includes a stable sub claim.
profilename, given_name, family_name, picture.
emailemail, email_verified.
offline_accessA refresh token alongside the access token.
Custom (e.g. invoices:read)Permission scopes you've defined in your resource catalog.

Add only what your app actually uses. Over-broad scopes leak data into tokens and bloat their size.

Token lifetimes#

All four are in seconds (except the two session/remember-me fields, which are in minutes). Defaults below match the dashboard.

SettingDefaultWhat it controls
accessTokenLifetime3600 (1 h)How long access tokens stay valid before needing refresh.
refreshTokenLifetime2592000 (30 d)Maximum age of refresh tokens.
authorizationCodeLifetime600 (10 min)How long an authorization code is valid for exchange — short on purpose.
sessionTimeoutMinutes480 (8 h)How long a Authaz Sign-In session stays usable. After this, users sign in again.
rememberMeTimeoutMinutes43200 (30 d)How long "Remember me" extends the session.

Picking access-token lifetime#

Shorter tokens = better revocation latency, more refresh round-trips. Longer = fewer round-trips, slower revocation when needed.

Use caseSuggested lifetime
High-security (banking, healthcare)5–15 min
Standard B2B SaaS30–60 min (default)
Long-running native apps where refresh is awkward2–4 h

Don't go above 24 h. Refresh tokens exist for the long-lived case.

Refresh-token rotation#

Authaz rotates refresh tokens by default — every successful refresh issues a new refresh token and invalidates the previous one. If your client retries an old refresh token, Authaz returns 400 invalid_grant and revokes the entire refresh-token family. This catches token theft.

Always store the refresh token returned in each response, not the original.

requireTenantHint#

{ "requireTenantHint": true }

When true, every OAuth authorize request must include a tenant_id parameter:

https://your-app.authaz.io/oauth2/authorize?
  client_id=YOUR_APP_ID
  &redirect_uri=...
  &tenant_id=tenant_acme         ← required
  &response_type=code
  &scope=openid+profile

Authaz will use that tenant for the entire authentication flow (Authaz Sign-In UX, provider routing, role resolution, the tenant_id claim on the issued tokens). Requests without tenant_id are rejected with 400 missing_tenant_hint.

Use this when:

  • Your app's URL structure already encodes the tenant (e.g. acme.yourapp.com calls /oauth2/authorize?tenant_id=tenant_acme).
  • You don't want users to see a tenant picker on Authaz Sign-In.
  • You're running isolated auth and the tenant must be known up front to pick the right providers.

Leave it false (the default) when:

  • A user might belong to multiple tenants and should choose at login time.
  • Your application is single-tenant (the parameter would be ignored anyway).

Session policy#

sessionTimeoutMinutes is the absolute lifetime of a Authaz Sign-In session — after this many minutes, the user must sign in again, no matter how active they are.

rememberMeTimeoutMinutes is the extended lifetime when the user clicks Remember me. The default of 43200 (30 days) is reasonable for most apps; banking and healthcare apps usually want this much shorter (~480 min, matching the regular session) or disabled entirely.

Both work in concert with the access-token lifetime: the access token is the per-request credential, the session is the cookie that lets Authaz Sign-In skip re-authentication on the next token request.

Application credential#

applicationCredentialId links this configuration to an OAuth client credential — the client_id and client_secret your app sends on POST /oauth2/token. The dashboard creates one for you on first save; you can also pre-create one under the API Keys page and link it here.

The credential carries:

  • client_id — public, included in every authorize URL.
  • client_secret — confidential, only sent server-side from your backend.

Rotate the secret when:

  • It's been leaked.
  • A team member with access leaves.
  • Annually as part of routine hygiene.

Rotation issues a new secret with a 24-hour grace period — both the old and new secrets work during that window so you can deploy without downtime.

Multi-tenant: per-tenant settings#

When Isolated Auth Stack is on, each tenant gets its own settings page with its own redirect URIs, token lifetimes, and requireTenantHint:

curl -X PUT https://your-app.authaz.io/api/v1/applications/{appId}/tenants/{tenantId}/universal-login \
  -H "X-API-Key: $AUTHAZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "redirectUris": ["https://acme.yourapp.com/auth/callback"],
    "accessTokenLifetime": 1800
  }'

Tenants without an override fall back to the application-level config.

Diagnosing common errors#

ErrorCauseFix
redirect_uri_mismatchThe callback URL isn't on redirectUris.Add it (exact match).
invalid_scopeA requested scope isn't on allowedScopes.Add it, or stop requesting it.
missing_tenant_hintrequireTenantHint is on, but tenant_id wasn't included.Add tenant_id= to the authorize URL.
invalid_grant on refreshRefresh token was rotated and an old one was used.Always use the latest refresh token from the most recent response.
code expiredMore than authorizationCodeLifetime seconds passed before exchange.Exchange codes immediately on callback; don't queue them.

Next steps#

  • Tokens — what's inside the access, ID, and refresh tokens these settings shape.
  • Tenancy Customization — when these settings can be overridden per tenant.
  • cURL quickstart — the OAuth flow these settings drive.