Auto-Discovery
OIDC Discovery Endpoint Your app can auto-discover all endpoints, supported scopes, signing algorithms, and capabilities from a single URL. Most OAuth libraries (NextAuth, Auth.js, Passport, etc.) only need this URL to configure themselves.
GET https://www.aicoo.io/.well-known/openid-configurationReturns a JSON document conforming to OpenID Connect Discovery 1.0 :
{
"issuer": "https://www.aicoo.io/api/auth",
"authorization_endpoint": "https://www.aicoo.io/api/auth/oauth2/authorize",
"token_endpoint": "https://www.aicoo.io/api/auth/oauth2/token",
"userinfo_endpoint": "https://www.aicoo.io/api/auth/oauth2/userinfo",
"jwks_uri": "https://www.aicoo.io/api/auth/jwks",
"revocation_endpoint": "https://www.aicoo.io/api/auth/oauth2/revoke",
"introspection_endpoint": "https://www.aicoo.io/api/auth/oauth2/introspect",
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"subject_types_supported": ["public", "pairwise"],
"id_token_signing_alg_values_supported": ["RS256"],
"scopes_supported": ["openid", "profile", "email", "offline_access"],
"code_challenge_methods_supported": ["S256"]
}Flow Overview
How It Works Pulse uses the OAuth 2.1 Authorization Code flow with PKCE. Here's the sequence:
1. Redirect
Your app redirects the user to Pulse's /authorize endpoint with client_id, redirect_uri, scope, state, and a PKCE code_challenge.
2. Authenticate
The user signs into their Pulse account (or is already signed in).
3. Consent
On first authorization, the user sees a consent screen showing the requested scopes. Subsequent authorizations skip this step.
4. Callback
Pulse redirects back to your redirect_uri with an authorization code and the original state.
5. Exchange
Your server exchanges the code for tokens at the /token endpoint (sending the code_verifier for PKCE validation).
6. Use tokens
Use the access_token to call /userinfo or other Pulse APIs. Decode the id_token for immediate claims.
Setup
Register an OAuth Client 1. Open Settings → Developer Portal .
2. Click "New Client" and fill in your app name and redirect URI.
3. Copy the client_id and client_secret immediately — the secret is shown only once.
4. Store them securely in your server environment.
PULSE_CLIENT_ID="UkshCwHgs..."
PULSE_CLIENT_SECRET="sk_live_..."
PULSE_ISSUER="https://www.aicoo.io"GET /api/auth/oauth2/authorize
Authorization Endpoint Initiates the OAuth 2.1 authorization code flow. Redirect the user's browser to this URL.
Parameters
Name Required Description response_typeYes Must be "code". client_idYes Your OAuth client ID. redirect_uriYes Must exactly match a registered redirect URI. scopeYes Space-separated list (e.g. "openid profile email"). stateYes Random string for CSRF protection. code_challengeYes Base64url-encoded SHA-256 hash of code_verifier. code_challenge_methodYes Must be "S256". nonceNo Random string included in the id_token for replay protection. promptNo "consent" forces the consent screen. "login" forces re-authentication.
Request Example
https://www.aicoo.io/api/auth/oauth2/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://yourapp.com/callback&
scope=openid%20profile%20email&
state=random_csrf_state&
code_challenge=BASE64URL_SHA256_HASH&
code_challenge_method=S256Successful Callback
https://yourapp.com/callback?code=AUTH_CODE&state=random_csrf_statePOST /api/auth/oauth2/token
Token Endpoint Exchange an authorization code for tokens, or refresh an expired access token. Request body must be application/x-www-form-urlencoded.
Authorization Code Exchange
curl -X POST https://www.aicoo.io/api/auth/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&\
code=AUTH_CODE&\
redirect_uri=https://yourapp.com/callback&\
client_id=YOUR_CLIENT_ID&\
client_secret=YOUR_CLIENT_SECRET&\
code_verifier=ORIGINAL_CODE_VERIFIER"Refresh Token Exchange
curl -X POST https://www.aicoo.io/api/auth/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token&\
refresh_token=REFRESH_TOKEN&\
client_id=YOUR_CLIENT_ID&\
client_secret=YOUR_CLIENT_SECRET"Response
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "rt_...",
"id_token": "eyJhbGciOi...",
"scope": "openid profile email"
}GET /api/auth/oauth2/userinfo
UserInfo Endpoint Returns claims about the authenticated user. Requires a valid access token with appropriate scopes.
Request
curl https://www.aicoo.io/api/auth/oauth2/userinfo \
-H "Authorization: Bearer ACCESS_TOKEN"Response
{
"sub": "a7f2c9e1-...",
"name": "Abhinav Jain",
"email": "abhinav@example.com",
"email_verified": true,
"picture": "https://..."
}Note: sub is a pairwise identifier unique to your client — it cannot be correlated across applications.
GET /api/auth/jwks
JSON Web Key Set Returns the public keys used to verify id_token and access_token signatures. Tokens are signed with RS256.
curl https://www.aicoo.io/api/auth/jwks{
"keys": [
{
"kty": "RSA",
"kid": "pulse-key-1",
"use": "sig",
"alg": "RS256",
"n": "...",
"e": "AQAB"
}
]
}POST /api/auth/oauth2/revoke
Token Revocation Revoke an access token or refresh token. Conforms to RFC 7009 .
curl -X POST https://www.aicoo.io/api/auth/oauth2/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=ACCESS_OR_REFRESH_TOKEN&\
client_id=YOUR_CLIENT_ID&\
client_secret=YOUR_CLIENT_SECRET"POST /api/auth/oauth2/introspect
Token Introspection Validate a token and retrieve its metadata server-side. Conforms to RFC 7662 .
curl -X POST https://www.aicoo.io/api/auth/oauth2/introspect \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=ACCESS_TOKEN&\
client_id=YOUR_CLIENT_ID&\
client_secret=YOUR_CLIENT_SECRET"Response (active token)
{
"active": true,
"sub": "a7f2c9e1-...",
"client_id": "YOUR_CLIENT_ID",
"scope": "openid profile email",
"exp": 1713100800,
"iat": 1713099900,
"token_type": "Bearer"
}Reference
Available Scopes Scope Claims Returned Required openidsub (unique user identifier) Yes, for OIDC profilename, picture No emailemail, email_verified No offline_accessIssues a refresh_token No
Security
PKCE (Proof Key for Code Exchange) PKCE is mandatory for all authorization requests. It prevents authorization code interception attacks.
1. Generate a code verifier — a random string of 43-128 characters (A-Z, a-z, 0-9, -, ., _, ~).
2. Generate a code challenge — Base64url-encode the SHA-256 hash of the code verifier.
3. Send code_challenge in the authorize request.
4. Send code_verifier in the token exchange request.
// Node.js example
const crypto = require('crypto');
const codeVerifier = crypto.randomBytes(32)
.toString('base64url');
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url');
// Send code_challenge to /authorize
// Send code_verifier to /tokenReference
Token Lifecycle Token Expiry Notes Authorization code 60 seconds Single-use. Must be exchanged immediately. Access token 15 minutes Used to call APIs. Signed with RS256. Refresh token 30 days Used to obtain new access tokens. Requires offline_access scope. ID token 1 hour JWT with user claims. Verify signature using JWKS.
Error Codes
OAuth Error Responses invalid_clientHTTP 401
Client ID not found or secret incorrect.
invalid_requestHTTP 400
Missing required parameter or malformed request.
invalid_grantHTTP 400
Authorization code expired, already used, or code_verifier mismatch.
invalid_scopeHTTP 400
Requested scope is not supported.
unauthorized_clientHTTP 403
Client not authorized for this grant type.
access_deniedHTTP 403
User denied the consent request.
server_errorHTTP 500
Unexpected server issue. Retry with exponential backoff.
Ready?
Start Building Head to the Developer Portal to register your first OAuth client and start integrating "Sign in with Pulse".
Open Developer Portal