13.2 Authentication
enum Principal {
User(id: UserId, roles: Set<AppRole>, claims: Map<str, str>, mfa: bool, tenant: str?)
Service(name: str, role: str)
Node(id: NodeId)
Anonymous
}- Providers are set in
cluster { auth { … } }:jwt(issuer, audience?, jwks?),oidc(issuer, clientId),apikey,session(cookie: name). User roles:roles from claim("roles") as AppRole.
Implementation-defined. OIDC (D-8055; DIV-025; D-4739). An optional feature: the provider
oidc(issuer, clientId). This implementation does not contain it; JWT verification byjwksor a given key (jwt(…)) is supported.
apikey— a key in a header (apikey(header: h),x-api-keyby default) or inAuthorization: ApiKey …; the server stores only the hash of the key, a key yields aPrincipal.User.session(cookie: name)— a server-side session:createSession(user, roles, ttl) -> str | SessionError(std.rpc) creates a session and returns the identifier that the client carries in the cookiename;endSession(id)ends it; settingSet-Cookieis up to the application. Order: Bearer (jwt) → key → session cookie; the first one presented decides; a presented but invalid credential isUNAUTHENTICATED, none at all isAnonymous. Credential headers do not get intoctx.metaand are not passed on (D-8065; D-8200..D-8202, D-8208).
Implementation-defined. Storage of keys and sessions (D-8065; DIV-025; D-8200, D-8201). This implementation: keys are a JSON file with SHA-256 (
OXL_AUTH_APIKEYS/--auth-apikeys; fieldsid,sha256,sub,roles,tenant,mfa,claims,expires), compared in constant time, reloaded when the file changes; no file means every key is rejected; a session is a record{exp, principal}under the hash of the identifier in the replicated storage, lifetime 1 ms..30 days.
- Verification is performed before entering the handler. A failure is
AccessDenied(UNAUTHENTICATED). - Services and nodes are identified by their mTLS certificate.
- Delegation: outgoing calls from a handler carry the original user (
ctx.caller) and the calling service (ctx.via). To narrow the rights:asScoped(caller.scoped([…])) { … }; to call on behalf of your own service:asService { … }. Calls of external services (S.connect(addr)) do NOT carry the identity of the user or of the service: the headersx-oxl-principalandx-oxl-userare not sent there, and theauthorizationof the inbound call is not forwarded (the application puts its own credential intoctx.metaif needed) (D-8066; D-8300).
Implementation-defined. Type of the user identifier (D-8056; DIV-049; D-2905).
UserIdinPrincipal.Userand inuserId()is an application type (for example,distinct u64) that the standard library does not know. This implementation stores the identifier inPrincipal.Userasstr(the value of the JWT claimsub);Ctx.userId()andisUseraccept and returnstr; the application parses it into its ownUserId(in V.5 by the functioncallerId(ctx)).
Methods of Principal: isUser(id: UserId?) -> bool (false for none and for a non-user), has(role: AppRole) -> bool, service(name: str) -> bool, userId() -> UserId | AccessDenied. In handlers ctx.userId() is shorthand for ctx.caller.userId(); in policies the principal is available as caller.
Related diagnostics
See also
Source: docs/spec/oxl-standard.en.md