Billabex uses OAuth 2.1 Authorization Code flow with PKCE for secure API access. OpenID Connect (OIDC) is available when you include the openid scope. This guide explains the flow, supported features, token lifetimes, refresh behavior, and all available endpoints.
Overview
At a high level, the flow looks like this:
- You create an OAuth client in the Developer Portal and configure allowed redirect URIs and scopes.
- Your app redirects the user to the authorization endpoint with PKCE parameters and requested scopes.
- The user signs in, reviews consent, and approves access.
- You receive an authorization code on your redirect URI.
- You exchange the code (plus the PKCE verifier) for tokens at the token endpoint.
- You call the API with the access token and refresh it when needed.
OAuth in Billabex is:
- User-centric: access is granted by a user
- Token-based: no API keys
- Scoped: permissions are explicit and minimal
- Time-bound: all tokens have a limited lifetime
Token Types and Lifetimes
Billabex issues several token types. Each has a specific purpose and a fixed TTL.
| Token Type | TTL (seconds) | TTL (human) | Description |
|---|---|---|---|
| Access Token | 3600 | 1 hour | Used to call the public API |
| Refresh Token | 2592000 | 30 days | Used to obtain new access tokens |
| Authorization Code | 600 | 10 minutes | Temporary code exchanged for tokens |
| ID Token (OIDC) | 600 | 10 minutes | Identity token (OIDC best practice) |
Notes:
- Access tokens are intentionally short-lived.
- Authorization codes and ID tokens follow OIDC security best practices.
- Expired tokens are rejected automatically.
OAuth Actors
An OAuth flow involves three parties:
- Resource Owner – the user granting access
- Client Application – your application
- Authorization Server – Billabex OAuth server
Your application never handles user credentials directly.
Supported OAuth 2.1 Features
Billabex follows OAuth 2.1 conventions with secure defaults.
- Authorization code flow only (
response_type=code) - PKCE required (
S256recommended,plainsupported for legacy clients) - Refresh tokens with rotation on every use
- Token endpoint authentication
nonefor public clientsclient_secret_basicorclient_secret_postfor confidential clients
- Dynamic client registration (RFC 7591 / 7592)
- Token revocation (RFC 7009)
The Developer Portal creates confidential clients by default and shows the client_secret only once.
OAuth Endpoints
All OAuth endpoints are under the API base URL.
Authorization
GET [baseURL]/api/oauth/authorize
Token
POST [baseURL]/api/oauth/token
Revocation
POST [baseURL]/api/oauth/revoke
UserInfo (OIDC)
GET [baseURL]/api/oauth/userinfo
Dynamic registration
POST [baseURL]/api/oauth/register
Client configuration management
GET/PUT/DELETE [baseURL]/api/oauth/register/{clientId}
Discovery and JWKS
Public endpoints at the root domain:
[baseURL]/.well-known/oauth-authorization-server[baseURL]/.well-known/openid-configuration[baseURL]/.well-known/jwks.json
Authorization Request
Redirect the user to the authorization endpoint with the following parameters:
client_id(required)redirect_uri(required, must match exactly)response_type=code(required)scope(recommended)code_challenge(required)code_challenge_method=S256(recommended)state(required)nonce(required when usingopenid)
Always validate state (and nonce for OIDC).
Authorization Code
After user approval, Billabex redirects back to your redirect_uri with:
codestate
The authorization code:
- Is valid for 10 minutes
- Can be used only once
Token Exchange (authorization_code)
POST [baseURL]/api/oauth/token
Required fields:
grant_type=authorization_codecoderedirect_uricode_verifierclient_idclient_secret(confidential clients)
Successful response:
{
"access_token": "...",
"refresh_token": "...",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "...",
"id_token": "..."
}
id_token is present only when openid is granted.
Refreshing Access Tokens
Access tokens expire after 1 hour.
Use the refresh token to obtain a new access token.
Refresh Token Rotation Policy
Billabex enforces refresh token rotation.
This means:
- Every refresh request revokes the previous refresh token
- A new refresh token is issued on each refresh
- Only the most recently issued refresh token remains valid
Important clarifications:
- Refreshing an access token does not revoke access by itself
- The refresh operation invalidates the previous refresh token
- You must persist the new refresh token immediately
- Reusing an old refresh token will fail
Refresh Token Request
POST [baseURL]/api/oauth/token
{
"grant_type": "refresh_token",
"refresh_token": "CURRENT_REFRESH_TOKEN",
"client_id": "CLIENT_ID",
"client_secret": "CLIENT_SECRET"
}
Response:
{
"access_token": "...",
"refresh_token": "...",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "..."
}
Accessing the API
Send the access token as a Bearer token in the Authorization header on all API calls.
Scopes are enforced per endpoint. Use the Scopes guide to request the minimum required permissions.
Token Revocation
Revoke tokens when a user disconnects your integration.
Fields:
tokentoken_type_hint(optional)
OpenID Connect (OIDC)
OIDC is enabled when the openid scope is requested.
OIDC Scopes
openidprofileemail
ID Token
- Returned only when
openidis granted - Must be validated (signature, issuer, audience, expiry, nonce)
UserInfo Endpoint
Returns user claims allowed by granted scopes.
Security Best Practices
- Always use HTTPS
- Always use PKCE
- Validate
stateandnonce - Store tokens securely
- Rotate refresh tokens atomically
- Never log tokens
- Request the minimum scopes needed
Next Steps
Support
Questions about OAuth or OIDC?
Contact us via the website contact form.