Skip to Content
We are live but in Staging πŸŽ‰
Auth and Access

Auth and Access

AppID has two doors with two different locks. Keep them straight and everything else follows.

Control plane β€” managing pools and users

Everything under dodil appid … / https://api.dodil.io/v1/appid/… is platform-authenticated: you sign in with dodil auth login and the gateway resolves your organization from your token. There is no --org flag and no organization field in any request.

Access is role-based:

RoleCan
appid.adminEverything β€” create/delete pools, rotate keys, manage connections, policies, users, user stores
appid.viewerRead β€” get/list pools, connections, users
org ownerAlways everything for their org’s pools, with no explicit grant

Grant the roles with platform IAM (dodil auth user grant-role), the same way as any other product role.

Fine-grained scopes behind the roles (what a permission check is actually named): CreatePool, GetPool, ListPools, DeletePool, RotatePoolKeys, ManageConnections, ListConnections, ManagePolicies, ManageUserStore, ManageAppUsers, ListAppUsers.

App plane β€” how end users authenticate

End users never see any of the above. They authenticate against the pool issuer (https://appid.dodil.io/{org}/{pool}), which is public and unauthenticated by design:

  1. Authorization code + PKCE (recommended) β€” your app redirects to {issuer}/authorize, the user signs in on the hosted page, your app exchanges the returned code at {issuer}/token. PKCE S256 is mandatory; plain and no-PKCE are refused. Tokens never pass through the browser URL.
  2. Direct grants β€” POST {issuer}/token with grant_type=password or refresh_token, for apps that own their login UI. JSON and form-encoded both accepted.
  3. Self-service β€” {issuer}/signup, {issuer}/recover (+ email link to /reset), {issuer}/verify for email confirmation.

The pool mints EdDSA JWTs your backend verifies locally against the pool JWKS β€” checking iss and aud β€” with no call back to AppID. Full endpoint contract: API Reference β†’ Issuer API.

Redirect URIs are an allowlist

{issuer}/authorize redirects only to URIs listed in the pool’s settings.redirect_uris. An unlisted redirect_uri gets an error page, never a redirect β€” so a stolen client_id can’t exfiltrate codes to an attacker’s site.

Matching is exact: scheme, host, port and path, with no query string. https is required except for http://localhost and http://127.0.0.1. One wildcard form is allowed: a single * as the whole leftmost host label, matching exactly one label. https://*.apps.example.com/.dodil/auth/callback matches https://fn1-org.apps.example.com/.dodil/auth/callback but not https://a.b.apps.example.com/.dodil/auth/callback; the path and port must still match exactly.

CORS is per-pool and exact

Browser JavaScript may call the JSON endpoints only from origins listed in policies.cors_allowed_origins. Matching is exact (scheme + host + port); no wildcard subdomains. No configured origins β†’ no CORS headers β†’ browser calls fail. Tokens are sent as Authorization: Bearer β€” AppID sets no auth cookies on your app’s behalf.

Anti-enumeration posture

Responses are shaped so an outsider can’t probe your user base: recover always answers 200 whether or not the email exists; signing in to a tenant you’re not a member of fails exactly like a wrong password.

Rate limits

Defaults, enforced per pool on the public surface (adjustable per pool in policies):

ActionBudget
Login attempts10 / min / email
Signups60 / min
Password-recovery emails5 / hour / email
Reset / verify codes60 / hour
/authorize opens120 / min / client IP
Client self-registration (/register)20 / hour (max 100 clients per pool)

Exceeding a budget returns 429; budgets are counted cluster-wide.

What AppID deliberately does not have

  • No dk_ API keys for app users. For machine-to-machine calls between your apps, a pool has service clients (dodil appid service-client create <pool> --client-id <id> --role <r>; client_credentials at {issuer}/token; the token’s sub is svc:<client_id>). To call Dodil products (K3, Models, …), your server uses a platform service account from IAM, not a pool token.
  • No pool-token access to Dodil products β€” a pool JWT is only meaningful to your app.
  • Password policy is minimum length only (8–128, per-pool) β€” there are no character-class rules today.