Three quickstarts, zero lock-in.
Obexal is a complete OIDC and OAuth 2.1 provider: discovery, JWKS, PAR, introspection and revocation sit exactly where the specifications put them. Start with three curl quickstarts, then go deeper in the documentation.
Add login to a web app
Authorization code with PKCE (S256): read the discovery document, send the user to the authorization endpoint, exchange the code.
# 1. Read the discovery document
curl -s https://accounts.obexal.com/.well-known/openid-configuration
# 2. Generate a PKCE verifier and its S256 challenge
CODE_VERIFIER=$(openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | cut -c1-64)
CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" \
| openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')
# 3. Send the user to the authorization_endpoint from discovery
# .../oauth/authorize?response_type=code&client_id=$CLIENT_ID
# &redirect_uri=$REDIRECT_URI&scope=openid+profile+email
# &code_challenge=$CODE_CHALLENGE&code_challenge_method=S256
# 4. Exchange the returned code for tokens
curl -s https://accounts.obexal.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "code=$AUTH_CODE" \
--data-urlencode "redirect_uri=$REDIRECT_URI" \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode "code_verifier=$CODE_VERIFIER"Protect a machine service
Client credentials for service-to-service calls. The secret comes from your environment or secret manager, never inline on the command line.
# CLIENT_SECRET is injected by your secret manager, never typed inline
curl -s https://accounts.obexal.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode "client_secret=$CLIENT_SECRET" \
--data-urlencode "scope=directory.read"
# Response
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "directory.read"
}Give an AI agent an identity
The agent authenticates with its own client credentials (PAR available at /oauth/par). Delegation has a proper name: Token Exchange, RFC 8693. The issued token carries the delegation chain in the act claim.
# 1. The agent gets its own token, capped by its scope ceiling and TTL cap
curl -s https://accounts.obexal.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=$AGENT_CLIENT_ID" \
--data-urlencode "client_secret=$AGENT_CLIENT_SECRET" \
--data-urlencode "scope=crm.read"
# 2. Delegation, properly named: Token Exchange (RFC 8693)
# The agent acts on behalf of a user; the token carries the act claim
curl -s https://accounts.obexal.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
--data-urlencode "subject_token=$USER_ACCESS_TOKEN" \
--data-urlencode "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
--data-urlencode "client_id=$AGENT_CLIENT_ID" \
--data-urlencode "client_secret=$AGENT_CLIENT_SECRET" \
--data-urlencode "scope=crm.read"Scope ceilings, kill switch and anomaly detection are covered in depth on AI agent identity.
Validate a token
Local validation against published keys when latency matters, introspection when revocation and the kill switch must be visible immediately.
# Option A: validate locally against the published keys
curl -s https://accounts.obexal.com/.well-known/jwks.json
# then check signature, exp, iss and aud in your JWT library
# Option B: server-side introspection (RFC 7662)
# Revoked tokens and agent kill switches show up here immediately
curl -s https://accounts.obexal.com/oauth/introspect \
--data-urlencode "token=$ACCESS_TOKEN" \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode "client_secret=$CLIENT_SECRET"Endpoints at a glance
- Discovery
- /.well-known/openid-configuration
- JWKS
- /.well-known/jwks.json
- Token
- /oauth/token
- Pushed authorization requests
- /oauth/par
- Introspection
- /oauth/introspect
- Revocation
- /oauth/revoke
- RP-initiated logout
- /oauth/logout
- Userinfo
- /oauth/userinfo
- SAML metadata
- /saml/idp/{tenant}/metadata
- SCIM users
- /scim/v2/Users
- Admin API contract (OpenAPI 3.1)
- /v1/openapi.json
The admin API is described by a public OpenAPI 3.1 contract: generate a client in your language instead of waiting for an SDK.
Provision users over SCIM
Inbound SCIM 2.0 covers the Users resource; groups are managed in the Obexal directory. Outbound SCIM provisions your downstream apps, with automatic deprovisioning.
POST /scim/v2/Users HTTP/1.1
Host: accounts.obexal.com
Authorization: Bearer $SCIM_TOKEN
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "marie.durand@example.com",
"name": { "givenName": "Marie", "familyName": "Durand" },
"active": true
}AI agents on the admin API side
Everything an agent does at the token endpoint is governed from the admin API.
Register an agent
Every agent gets its own client credentials, a human owner, an expiry date and lifecycle states (active, dormant, expired, orphaned).
Fail-closed ceilings
A scope ceiling and a maximum TTL per agent: any request beyond them is refused, never silently degraded.
Immediate kill switch
Cut an agent off in one call: tokens already issued turn inert at introspection. Secrets are renewed and expire on schedule.
Practical, and honest
Sandbox
The free trial doubles as a sandbox: 30 days, no credit card.
Service status
Service health is published continuously.
Changelog
Every notable API and product change is published.
TypeScript SDK
A zero-dependency TypeScript SDK exists, aimed at the browser. Server side, the API is plain HTTP from any language, or a client generated from the OpenAPI contract.
Developer FAQ
Which grant types are supported?
Authorization code with PKCE (S256) for user-facing apps, client credentials for services and agents, and Token Exchange (RFC 8693) for delegation. Pushed Authorization Requests are available at /oauth/par.
How do confidential clients authenticate?
With client_secret or private_key_jwt. DPoP is supported to bind a token to a key held by the client.
How do I validate access tokens?
Locally with the keys from /.well-known/jwks.json, or server side with introspection (RFC 7662) at /oauth/introspect. Revoke at /oauth/revoke.
Is there an SDK?
A zero-dependency TypeScript SDK exists, aimed at the browser. Server side we made a deliberate choice: strict standards plus a public OpenAPI 3.1 contract at /v1/openapi.json, from which you generate a client in your language.
How does SCIM work?
Inbound SCIM 2.0 exposes the Users resource at /scim/v2/Users; groups are managed in the Obexal directory. Outbound SCIM provisions downstream apps, with automatic deprovisioning on suspension and audited failures.
How do I give an AI agent an identity?
Each agent has its own client credentials, with PAR as an option. Acting on behalf of a user goes through Token Exchange (RFC 8693), with a chained act claim and downscoping. Ceilings, kill switch and anomaly detection: see AI agent identity.
Is there a test environment?
The free trial doubles as a sandbox: 30 days, no credit card, at accounts.obexal.com. Service status lives at /status/ and changes at /changelog/.
Where is it hosted?
Obexal is hosted in France, in a datacenter in the Paris region, with EU data residency. No non-EU dependency in the request path, no external CDN, self-hosted fonts. TLS 1.2 minimum, 1.3 preferred.
Everything else is in the docs.
Quickstarts, endpoint references and guides: everything above is covered in depth.