How it works
Detailed overview of AgeOnce age verification flow
How AgeOnce Works
AgeOnce uses the standard OAuth 2.0 Authorization Code Flow for age verification. This ensures security and compatibility with most systems.
Flow Overview
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Your site │ │ AgeOnce │ │ User │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ 1. Redirect │ │
│──────────────────►│ │
│ │ 2. Verification │
│ │◄─────────────────►│
│ │ │
│ 3. Callback+code │ │
│◄──────────────────│ │
│ │ │
│ 4. Token request │ │
│──────────────────►│ │
│ │ │
│ 5. JWT token │ │
│◄──────────────────│ │
│ │ │
│ 6. Access │ │
│───────────────────────────────────────►Detailed Steps
1. Initiate verification
When a user attempts to access age-restricted content, your site redirects them to AgeOnce:
https://app.ageonce.com/?client_id=...&redirect_uri=...&state=...Parameters:
client_id— unique identifier of your clientredirect_uri— where to return the user after verificationstate— random string for CSRF attack protection
2. Biometric verification
On the AgeOnce page, the user undergoes biometric age verification:
- User grants camera permission
- System analyzes biometric data
- Age compliance is determined
Privacy: Biometric data is processed in real-time and not stored. We only store the fact of successful verification.
3. Callback with authorization code
After successful verification, the user is redirected back to your site:
https://yoursite.com/callback?code=abc123&state=xyz789Important: Always verify that state matches what you sent!
4. Exchange code for token
Your backend exchanges the authorization code for an age token:
POST https://api.ageonce.com/api/oauth/token
Content-Type: application/json
Authorization: Basic base64(client_id:client_secret)
{
"grant_type": "authorization_code",
"code": "authorization_code",
"redirect_uri": "https://yoursite.com/callback",
"state": "the_state_you_sent"
}The authorization code can only be used once and is valid for 1 minute.
5. Receive JWT token
The response contains a JWT token with age information:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 600,
"transaction_id": "550e8400-e29b-41d4-a716-446655440000"
}Response fields:
transaction_id— Audit ID for compliance; searchable in Dashboard Audit Logs
Token structure (payload):
{
"iss": "https://ageonce.io",
"aud": "ap_live_your_client_id",
"sub": "user-id",
"age_verified": true,
"age_over": 18,
"verification_level": "first_verification",
"verification_id": "550e8400-e29b-41d4-a716-446655440000",
"reverification": false,
"iat": 1739275200,
"exp": 1739275800
}Payload fields:
aud— your client IDage_over— age threshold that was verified (for example 18 or 21)verification_id— same astransaction_id; use for audit trail
6. Grant access
Based on age_verified and age_over, you decide whether to grant access to content:
if (payload.age_verified && payload.age_over >= 18) {
// Grant access to 18+ content
}Token Validation
Option A: Via API
GET https://api.ageonce.com/api/verify/token/{access_token}Advantages: Simpler, no need to store keys
Disadvantages: Additional HTTP request
Option B: Local validation
- Get the public key from
https://api.ageonce.com/api/.well-known/jwks.json - Validate JWT signature locally
Advantages: Faster, less API load
Disadvantages: Need to cache and update keys
Security
JWT signature
Tokens are signed with RS256 algorithm (RSA + SHA-256). This ensures:
- Token cannot be forged
- Token cannot be modified
Lifetime
- Authorization code: 1 minute
- Access token: 10 minutes
Recommendations
- Always verify the
stateparameter - Store
client_secretsecurely (server-side only) - Validate tokens before use
- Use HTTPS for all requests