Skip to main content

Hosts and purposes

Ave separates user-facing pages, API calls, and organization administration. Mixing the sign-in host and API host is the #1 integration mistake.
HostUsed for
aveid.netUser-facing pages (sign-in, Connector consent), OIDC discovery, JWKS
api.aveid.netAPI calls (token exchange, userinfo, signing)
business.aveid.netBusiness organization membership, wrapped org keys, verified domains, and SSO setup
✅ POST https://api.aveid.net/api/oauth/token
✅ GET  https://aveid.net/.well-known/openid-configuration
❌ POST https://aveid.net/api/oauth/token   ← token API is on api.aveid.net

Identity model

When a user signs in with Ave, they sign in as a specific identity — not just a user account. The same person can have multiple identities.
ConceptDescription
identityIdStable UUID for an identity. Use this as your primary key for user data.
handleThe identity’s username (e.g. alice). Can be changed by the user.
Don’t store data keyed by handle — it can change. Always use identityId (the sub claim in JWTs) as your stable identifier.

Token types

A successful token exchange returns up to four tokens, each with a different purpose:
An opaque string accepted by Ave’s own API endpoints (mainly /api/oauth/userinfo). Not a JWT — you cannot decode it. It expires after 1 hour.
access_token: "ave_at_..."
A signed JWT with aud: https://aveid.net. Use this when calling Ave API endpoints that accept JWTs, or as the subject token for Connector token exchange. Do not use it as the login token for your app API; use id_token or your own app session for that.
access_token_jwt: "eyJ..."
Verify using the jwks_uri from your issuer’s OIDC discovery document ({issuer}/.well-known/openid-configuration). For Ave, this is https://aveid.net/.well-known/jwks.json.
A signed JWT with aud set to your clientId. Use this to establish a user session in your app, or with OIDC-aware services like Convex. Only returned when openid scope is granted.
id_token: "eyJ..."
An opaque token you can exchange for a fresh set of access/ID tokens without re-authenticating the user. Only returned when offline_access scope is granted. Rotated on every use — store the new one immediately.
refresh_token: "rt_..."
id_token and access_token_jwt are both JWTs but have different audiences. The id_token audience is your clientId. The access_token_jwt audience is https://aveid.net. This matters for any library that validates JWT audience.

Scopes

Scopes are space-separated strings requested during authorization. They control what claims appear in tokens and what resources can be accessed.
ScopeWhat it unlocks
openidReturns id_token. Required for OIDC flows.
profileAdds name, preferred_username, picture to userinfo
emailAdds email to userinfo
offline_accessReturns refresh_token for long-lived sessions
user_idReturns raw userId — only available if the app has this scope enabled
Scopes are allowlisted per app. Requesting a scope your app hasn’t been granted will return an invalid_scope error.

Token endpoint field casing

The Ave token endpoint (POST /api/oauth/token) accepts both OAuth-standard snake_case body fields and legacy camelCase variants.
{
  "grant_type": "authorization_code",
  "client_id": "YOUR_CLIENT_ID",
  "redirect_uri": "...",
  "code_verifier": "..."
}
Prefer the standard snake_case names in new integrations. Legacy grantType, clientId, redirectUri, and codeVerifier still work for backward compatibility.
Last modified on May 23, 2026