codai docs
Auth

Sign in with codai

auth.codai.ro is a standard OpenID Connect provider. Use it when your app needs to act on behalf of a codai user; use a plain API key when it does not.

https://auth.codai.ro is codai's identity provider — a standards-compliant OpenID Connect server with discovery, PKCE, refresh tokens, RP-initiated and back-channel logout. Every codai account signs in through it (password, passkey, magic link or Google), and every first-party surface — hub, pay, docs, the desktop and phone apps — is a relying party of it.

For you as an integrator it does one thing the rest of OIDC does not: after a user signs in and consents, GET /connect/key mints a gateway API key bound to that user and that consent, so your app can call https://ai.codai.ro as them — billed to their plan, revocable by them, without ever seeing their password or their other keys.

Do you need it?

You are building…Use
A server, script, bot or CI job that calls codai as youA plain API key from hub.codai.ro → Keys. No OIDC. See the gateway quickstart.
An app where each of your users brings their own codai account and pays for their own usageConnect with codai — the connect flow. One redirect, one token exchange, one GET /connect/key.
A web app that just needs to know who the codai user is (SSO), no inferenceStandard OIDC code flow; request openid email profile and read the ID token.
An MCP client that should reach codai tools and memoryOIDC with the mcp scope against resource https://ai.codai.ro/mcp; clients may self-register via Dynamic Client Registration.
A CLI without a browser on the same machineThe device-authorization grant is implemented but only provisioned for first-party clients today — ask.

Discovery

curl -s https://auth.codai.ro/.well-known/openid-configuration | jq '{issuer, authorization_endpoint, token_endpoint, userinfo_endpoint, jwks_uri, end_session_endpoint, grant_types_supported, code_challenge_methods_supported, token_endpoint_auth_methods_supported, scopes_supported}'
EndpointPath
AuthorizationGET /auth
TokenPOST /token — throttled at 60 requests/min per IP (429 { "error": "rate_limited" })
UserInfoGET /me
JWKSGET /jwks — every non-revoked RS256 key; the newest signs
Introspection / revocationPOST /token/introspection, POST /token/revocation
End sessionGET /session/end
Dynamic registrationPOST /reg (public clients only)
Device authorizationPOST /device/auth
Mint a gateway keyGET /connect/key — codai-specific, see the connect flow

Facts worth knowing before you write code:

  • PKCE (S256) is required for every client, public or confidential. There is no implicit or hybrid flow; response_type is always code.
  • Client authentication methods: none (public), client_secret_basic, client_secret_post, private_key_jwt. client_secret_jwt is not offered.
  • Grant types: authorization_code, refresh_token, urn:ietf:params:oauth:grant-type:device_code.
  • Token lifetimes: access token 1 h, ID token 1 h, authorization code 10 min, refresh token 30 days rotating (≤ 1 year total), consent grant 90 days, IdP browser session 14 days.
  • Refresh tokens are issued only when the client has the refresh_token grant and the request asked for offline_access. Public clients always rotate on use.
  • Access tokens for the default resource (https://ai.codai.ro/v1) are opaque — validate them with introspection or just use them at /connect/key. Tokens for https://ai.codai.ro/mcp are RS256 JWTs the gateway verifies locally.
  • Step-up: acr_values accepts urn:codai:acr:pwd, urn:codai:acr:passkey, urn:codai:acr:mfa; the IdP re-prompts if the session's method is weaker or older than 10 minutes.

Registering a client

There is no self-serve client registration for the connect flow yet — clients are provisioned by the codai team. Send us the client name, the exact redirect URIs (no wildcards; http:// only on loopback), whether the client is public (none) or confidential (client_secret_basic, client_secret_post or private_key_jwt), and the scopes you need. You get a client_id and, for confidential clients, a secret shown once.

MCP clients are the exception: POST /reg accepts RFC 7591 registrations without an initial access token, creating a public client (dcr_…) with 1 – 5 https:// / loopback / custom-scheme redirect URIs and the authorization_code grant.

Logout

  • RP-initiated: send the browser to GET /session/end?id_token_hint=<id_token>&post_logout_redirect_uri=<registered>&state=<yours>. The redirect URI must be registered exactly (no query string — carry your local target in state). Without id_token_hint the IdP shows a confirmation page first.
  • Back-channel: if your client registered a backchannel_logout_uri, the IdP POSTs a logout_token (form-encoded, matched on sid) when the user's session ends anywhere. Answer 200 or 204.

Revoking the consent — the user disconnecting your app, or an admin revoking the grant — also revokes any gateway key minted for it. Your stored codai_… key will start returning 401 invalid_api_key; treat that as "ask the user to connect again".

On this page