AgeOnce Docs

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/verify?client_id=...&redirect_uri=...&state=...

Parameters:

  • client_id — unique identifier of your client
  • redirect_uri — where to return the user after verification
  • state — random string for CSRF attack protection

2. Biometric verification

On the AgeOnce page, the user undergoes biometric age verification:

  1. User grants camera permission
  2. System analyzes biometric data
  3. 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=xyz789

Important: Always verify that state matches what you sent!

4. Exchange code for token

Your backend exchanges the authorization code for an age token:

POST /api/oauth/token
Content-Type: application/json

{
  "client_id": "your_client_id",
  "client_secret": "your_client_secret",
  "code": "authorization_code",
  "redirect_uri": "https://yoursite.com/callback"
}

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:

{
  "age_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 600,
  "transaction_id": "550e8400-e29b-41d4-a716-446655440000"
}

Response fields:

Token structure (payload):

{
  "sub": "anonymous",
  "age_verified": true,
  "min_age": 18,
  "age_over": 18,
  "verification_id": "550e8400-e29b-41d4-a716-446655440000",
  "verified_at": "2026-02-11T12:00:00Z",
  "client_id": "your_client_id",
  "iat": 1739275200,
  "exp": 1739361600,
  "iss": "ageonce"
}

Payload fields:

  • verification_id — same as transaction_id; use for audit trail

6. Grant access

Based on age_verified, you decide whether to grant access to content:

if (payload.age_verified && payload.min_age >= 18) {
  // Grant access to 18+ content
}

Token Validation

Option A: Via API

POST /api/oauth/validate
Content-Type: application/json

{
  "token": "eyJhbGciOiJSUzI1NiIs..."
}

Advantages: Simpler, no need to store keys
Disadvantages: Additional HTTP request

Option B: Local validation

  1. Get the public key from /api/oauth/jwks
  2. 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
  • Age token: 10 minutes

Recommendations

  1. Always verify the state parameter
  2. Store client_secret securely (server-side only)
  3. Validate tokens before use
  4. Use HTTPS for all requests

On this page