Authentication
Every ScaiDrive request (except /health and public share-link endpoints) needs a Bearer token issued by ScaiKey. This page covers how to get one and how to keep using it.
Token format#
ScaiDrive tokens are standard RS256- or ES256-signed JWTs issued by ScaiKey. The server validates them on every request by fetching ScaiKey's JWKS and verifying the signature.
Claims ScaiDrive reads:
| Claim | Meaning |
|---|---|
sub |
User ID (usr_...) |
tenant_id |
Tenant the user belongs to (tnt_...) |
partner_id |
Partner (managed service provider) the tenant belongs to |
email, name |
Profile |
groups |
Array of group IDs (grp_...) |
scope |
Space-separated scopes — see below |
iss |
Must match ScaiKey's URL (or the tenant-scoped issuer {scaikey}/tenants/{tenant_id}) |
exp |
Expiration — expired tokens are rejected with 401 |
act |
RFC 8693 actor claim. Present when the token reached us through a token-exchange flow (e.g., ScaiSpeak acting on behalf of a user). ScaiDrive reads act.client_id (falling back to act.sub) and records it on every audit event as service_account, so the audit trail names the delegating service alongside the acting user. The audience claim (aud) is not checked — narrow audience at exchange time for ScaiKey's records, but ScaiDrive doesn't gate on it |
Scopes#
ScaiDrive recognizes these application scopes:
| Scope | Grants |
|---|---|
files:read |
Read files, list folders, list shares |
files:write |
Create, update, delete files and folders |
tenant:admin |
Manage users, groups, quotas, connectors within the tenant |
partner:admin |
Manage all tenants owned by the caller's partner |
admin:* |
Full platform admin |
* |
Superuser (reserved for platform operators) |
A token with no application scopes gets tenant:admin by default on the assumption that ScaiKey already gates who can call ScaiDrive — i.e., ScaiKey is the enforcement point for "is this user allowed to use ScaiDrive at all." You can narrow the scope at token-issue time if you want to restrict a service token.
OIDC scopes like openid, profile, email, offline_access are recognized but not used for authorization — they only matter to ScaiKey.
How end users get a token#
End users don't get tokens directly — their client does, through OAuth 2.0 Authorization Code with PKCE. The flow:
- Client calls
GET /api/v1/auth/configto discover ScaiKey's authorize/token URLs and the registered client ID. - Client generates a PKCE code verifier and challenge, redirects the user to ScaiKey's authorize endpoint.
- User completes SSO at ScaiKey. ScaiKey redirects to the registered callback URL with an authorization code.
- Client exchanges the code at
POST /api/v1/auth/token(ScaiDrive proxies this to ScaiKey so clients only need the ScaiDrive URL). - Response contains
access_token,refresh_token,expires_in.
The web client does this automatically. The desktop and mobile clients do it via a browser pop-up. For your own integration, the OAuth dance only matters if you're building another end-user app.
Discover OAuth config#
1 | |
1 2 3 4 5 6 | |
Exchange authorization code#
1 2 3 4 5 6 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
1 2 3 4 5 6 7 8 9 10 11 | |
Response:
1 2 3 4 5 6 7 | |
How services get a token#
For machine-to-machine (a backend service calling ScaiDrive), ask your tenant admin to create a service token in ScaiKey. Service tokens belong to a synthetic user — no human interaction, no refresh flow required — and have a long or configurable lifetime.
Use it the same way as a user token:
1 2 | |
Never put service tokens in client-side code. A JavaScript bundle in a browser leaks the token to anyone who opens DevTools. Keep service tokens on the server.
Refreshing a token#
Access tokens expire (default: 1 hour). Refresh tokens last longer and rotate on use.
1 2 3 4 | |
1 2 3 4 5 | |
Your client should refresh proactively before expiration, or reactively when a request returns 401 AUTH_TOKEN_EXPIRED. Don't busy-refresh — if a refresh fails, the user re-authenticates.
Authorization — what the token is allowed to do#
Authentication answers "who is this request from." Authorization answers "what can they do." ScaiDrive resolves authorization in this order:
- Global admin role. Users with the
super_adminrole (set in the ScaiDrive database, not in the JWT) can do anything.tenant_admincan do anything within their tenant. - Share membership. The user's role in the share (
owner,admin,contributor,reader) defines the default permissions for every resource in that share. - ACL entries. Files and folders can override share-level permissions with per-resource allow/deny entries. Inheritance applies unless explicitly broken.
- External link scope. Requests authenticated with a link token (not a user JWT) are restricted to the link's allowed actions and resource scope.
See Permissions and ACLs for the full resolution rules.
JIT provisioning#
The first time a user presents a valid ScaiKey JWT that ScaiDrive has never seen, ScaiDrive creates a local user record automatically. No admin action is needed.
Subsequent ScaiKey webhooks on user.updated, group.updated, etc. keep the local records in sync. If you disable a user in ScaiKey, ScaiDrive sees the webhook, marks them suspended, and subsequent requests with their (still-unexpired) JWT fail with AUTHZ_USER_SUSPENDED.
What's next#
- Your First Integration — end-to-end integration example.
- Authentication Reference — all auth endpoints in detail.
- Permissions and ACLs — the authorization model.