Applications
An application in ScaiKey is an OAuth/OIDC client — anything that obtains tokens. Every external system that integrates with ScaiKey is registered as an application.
You pick two things at registration time: the type (which determines which grants the app can use) and the scope (which determines which tenants it can act on).
Application types#
| Type | Confidential? | Has a secret? | Use case |
|---|---|---|---|
WEB |
Yes | Yes | Web app with a backend (PHP, Rails, Django, Express) |
SERVICE |
Yes | Yes | Backend service that calls APIs but never serves a browser |
SPA |
No (public) | No | Single-page app running in the browser (React, Solid, Vue) |
NATIVE |
No (public) | No | Mobile or desktop app (iOS, Android, Electron) |
Confidential vs public matters because public clients can't safely hold a client_secret — anyone can decompile the app and read it. Public clients are required to use PKCE on the authorization_code flow and cannot use client_credentials at all.
Confidential clients (WEB, SERVICE) can use every grant including client_credentials and Token Exchange.
Application scope#
Determines the breadth of what an app's tokens can address:
| Scope | Lives at | Tokens can act on | Who can register |
|---|---|---|---|
GLOBAL |
Platform-level (no tenant) | Any tenant in the platform | super_admin only |
PARTNER |
Owned by a partner | Tenants under that partner | super_admin or that partner_admin |
TENANT |
Owned by a tenant | Only that tenant | tenant_admin of that tenant (or any higher admin) |
GLOBAL apps use the platform OAuth endpoints (/api/v1/platform/oauth/...); TENANT apps use tenant-scoped endpoints (/api/v1/auth/tenants/{slug}/oauth/...); PARTNER apps currently use tenant-scoped endpoints with an explicit tenant in the URL.
Per-application configuration#
When you register an app, you set:
redirect_uris— the exact URIs the OAuth flow may redirect to after login. Exact match (no wildcards, no path globs). Mismatches reject the request.logout_uris— acceptedpost_logout_redirect_urivalues for RP-initiated logout.allowed_origins— CORS origins for browser-based clients. ScaiKey's CORS middleware checks these dynamically (registered origins are allowed even if not in the static settings list).allowed_scopes— the scope superset this app may ever request. A token request can only get scopes that are in this list. To add a new scope to an existing app, update this list viaPATCH /api/v1/admin/applications/{id}.token_lifetime— access token TTL in seconds (default 3600). Configurable per app.refresh_token_lifetime— refresh token TTL (default 2592000, 30 days).token_exchange_allowed— boolean opt-in to be a target of Token Exchange. False by default; asuper_adminflips this on for trusted downstream services.sync_webhook_url+sync_webhook_secret— optional per-app webhook endpoint that receives events relevant to users/groups assigned to this app (see Reference → Webhooks).assigned_users,assigned_groups— explicit assignments for apps that gate access on user/group membership rather than open registration.
Identifiers#
client_id— the OAuth identifier. A randomly generated string (not prefixed; e.g.cp5pk59e0qnx4hwmvtw37ly6jnbx52uv). Show it to humans, log it, embed it in tokens — it's not a secret.client_secret— shown once at registration. Hash-stored in the database after that; if lost, generate a new one (which invalidates the old).- Internal
id—app_xxxxx. Used in the admin API path (/api/v1/admin/applications/app_xxxxx). Not used in OAuth flows.
Common patterns#
- Web app with backend, users log in via browser →
WEB+TENANTscope (orGLOBALif cross-tenant) +authorization_codegrant. - Backend service calling ScaiKey's admin API →
SERVICE+GLOBAL+client_credentials+admin:read(and/oradmin:write) inallowed_scopes. - Browser-only SPA →
SPA+TENANT+authorization_code+ PKCE. - CLI tool a user runs locally →
NATIVE+TENANT+device_code. - Long-running async job that calls a downstream service hours after user request → register the caller (
SERVICEconfidential) and the target (SERVICE, withtoken_exchange_allowed = true); use Token Exchange at request time, cache the exchanged token, retrieve in the worker.