Security and Authorization

Back to API Overview

This page covers the shared client responsibilities that apply before and after calling protected endpoints.

Base URL

The API exposes partition-specific base URLs for the active environment. Clients should use the API host presented by the current documentation build and avoid hard-coding a specific partition unless the workflow explicitly requires it.

Authentication

The platform uses Cognito-backed authentication for browser and application clients. In practice, clients should expect:

Tokens may be issued before initial account setup is complete so the user can finish Cognito-side onboarding. Until email is verified and either SMS/phone, TOTP setup, or federated identity-provider authentication is complete, normal platform APIs may reject the token with 401_116 Unauthorized_IncompleteAccountSetup.

For browser-driven sign-in, follow the endpoint-specific contracts in the Security > OAuth section of the sidebar.

Access Token Claims

ĀYŌDÈ user-facing APIs expect a Cognito access token. In addition to standard Cognito claims, the platform pre-token trigger adds the following claims to the access token when source values are available:

Claim Meaning
email User email address copied into the access token for API use.
email_verified Cognito email verification flag.
phone_number User phone number, when present.
phone_number_verified Cognito phone-number verification flag.
preferred_username Cognito preferred username, when present.
ayode:userEID Platform user external identifier. This claim is absent until the platform has propagated the user EID to Cognito and the user has refreshed the JWT.
ayode:email_verified Platform-computed email setup status.
ayode:phone_number_verified Platform-computed phone/SMS setup status. SMS MFA setup can satisfy this claim even when Cognito has not separately marked the raw phone number as verified.
ayode:totp_verified Platform-computed TOTP setup status.
ayode:is_federated_user Whether the user authenticated through a federated identity provider.
ayode:account_setup_complete Whether the user has completed the account setup requirements used by protected platform APIs.

The access token also receives the ayode.institute/api.user scope. Clients should treat the ayode:* claims as platform claims and refresh the token before assuming newly established platform state is present. Chat SSE routing, for example, requires ayode:userEID; if GET /v1/chat/events returns 404 with no recipient identity, refresh the JWT and reconnect.

Sample Authorization header:

Authorization: Bearer eyJraWQiOiJleGFtcGxlIiwiYWxnIjoiUlMyNTYifQ.eyJ0b2tlbl91c2UiOiJhY2Nlc3MiLCJzY29wZSI6ImF5b2RlLmluc3RpdHV0ZS9hcGkudXNlciIsInN1YiI6ImV4YW1wbGUtY29nbml0by1zdWIiLCJjbGllbnRfaWQiOiJleGFtcGxlLWNsaWVudCIsInVzZXJuYW1lIjoiZXhhbXBsZS11c2VyIiwiZW1haWwiOiJzdHVkZW50QGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOiJ0cnVlIiwicGhvbmVfbnVtYmVyIjoiKzE1NTU1NTUwMTAwIiwicGhvbmVfbnVtYmVyX3ZlcmlmaWVkIjoiZmFsc2UiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzdHVkZW50LW9uZSIsImF5b2RlOnVzZXJFSUQiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAiLCJheW9kZTplbWFpbF92ZXJpZmllZCI6InRydWUiLCJheW9kZTpwaG9uZV9udW1iZXJfdmVyaWZpZWQiOiJ0cnVlIiwiYXlvZGU6dG90cF92ZXJpZmllZCI6ImZhbHNlIiwiYXlvZGU6aXNfZmVkZXJhdGVkX3VzZXIiOiJmYWxzZSIsImF5b2RlOmFjY291bnRfc2V0dXBfY29tcGxldGUiOiJ0cnVlIn0.signature

Decoded payload shape:

{
  "token_use": "access",
  "scope": "ayode.institute/api.user",
  "sub": "example-cognito-sub",
  "client_id": "example-client",
  "username": "example-user",
  "email": "student@example.com",
  "email_verified": "true",
  "phone_number": "+15555550100",
  "phone_number_verified": "false",
  "preferred_username": "student-one",
  "ayode:userEID": "00000000-0000-0000-0000-000000000000",
  "ayode:email_verified": "true",
  "ayode:phone_number_verified": "true",
  "ayode:totp_verified": "false",
  "ayode:is_federated_user": "false",
  "ayode:account_setup_complete": "true"
}

OAuth Login Paths

Two distinct OAuth entrypoints exist:

/v1/auth/login does not accept a caller-supplied redirect URI and is not a generic localhost handoff endpoint.

Development Loopback OAuth

In the development silo, developer tools such as Postman or IDE HTTP clients may complete OAuth directly against the Cognito hosted UI by using the public web client with authorization code flow and PKCE.

Approved exact-match loopback callback and logout URIs:

Production does not permit any loopback callback or logout URI.

Realm Assertion

Many endpoints require the client to assert the acting realm. Supported headers include:

Only one assertion header should be sent on a given request.

Authorization Model

Authorization is privilege-based, scope-aware, and predicate-aware.

Important concepts:

Common scope patterns:

Each privilege is evaluated as an action, scope, and predicate tuple. A privilege written as /teams/update{realm} is equivalent to /teams/update{realm | ⊤}: the action and scope must match, and the predicate ⊤ is always satisfied. The predicate ⊥ is also valid, but it is never satisfied and therefore never authorizes a request.

Predicate expressions model business relationships. Examples include:

The variable p is the authenticated principal. A term such as team(eid) means that the endpoint being authorized must provide the team identifier for the request. The predicate catalog exposes those requirements through requiredContextVariableNames; for example, predicates over team(eid) require teamEID, and predicates over teamMembershipRequest(eid) require teamMembershipRequestEID.

Clients do not send a generic authorization-context object. Context values come from the endpoint contract being executed, such as a path parameter, request body field, or server-resolved resource relationship. If an endpoint uses a predicate but cannot provide every required context variable, authorization fails explicitly instead of silently falling back to action-and-scope-only authorization.

At request time, authorization checks proceed in order:

  1. Match the requested privilege action.
  2. Verify that the privilege scope applies to the asserted realm and target.
  3. Match the privilege predicate expression assigned to the grant.
  4. Evaluate the predicate using the endpoint-specific context values.

Failure responses remain diagnosable. A denied request may reflect a missing privilege, invalid scope, missing predicate assignment, missing required context, or a predicate that evaluated to false.

Use GET /v1/privilege-predicates to list the predicate catalog, including each predicate URN, display expression, required context variables, and localized display name. Use the predicate URN as predicateExpressionURN when creating or updating v2 privileges.

Response Envelope

Most successful JSON responses are wrapped in a shared envelope plus operation data payload.

Expect envelope metadata such as:

Permission Recipes

Two recurring permission-check patterns are especially important for client integrators:

If behavior is unexpected, verify both the asserted realm and the effective privilege scope.

Verification and Troubleshooting

Useful troubleshooting practices:

For the generated cross-endpoint privilege summary, see Endpoint Privileges Map.

Paging

List endpoints commonly use page-number plus items-per-page semantics. Clients should treat paging fields as part of the shared response contract and avoid assuming that a single page contains the full dataset.

Where To Go Next