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 you | A 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 usage | Connect 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 inference | Standard OIDC code flow; request openid email profile and read the ID token. |
| An MCP client that should reach codai tools and memory | OIDC 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 machine | The 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}'| Endpoint | Path |
|---|---|
| Authorization | GET /auth |
| Token | POST /token — throttled at 60 requests/min per IP (429 { "error": "rate_limited" }) |
| UserInfo | GET /me |
| JWKS | GET /jwks — every non-revoked RS256 key; the newest signs |
| Introspection / revocation | POST /token/introspection, POST /token/revocation |
| End session | GET /session/end |
| Dynamic registration | POST /reg (public clients only) |
| Device authorization | POST /device/auth |
| Mint a gateway key | GET /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_typeis alwayscode. - Client authentication methods:
none(public),client_secret_basic,client_secret_post,private_key_jwt.client_secret_jwtis 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_tokengrant and the request asked foroffline_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 forhttps://ai.codai.ro/mcpare RS256 JWTs the gateway verifies locally. - Step-up:
acr_valuesacceptsurn: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 instate). Withoutid_token_hintthe IdP shows a confirmation page first. - Back-channel: if your client registered a
backchannel_logout_uri, the IdPPOSTs alogout_token(form-encoded, matched onsid) when the user's session ends anywhere. Answer200or204.
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".