API Reference
Token Validation
Age token validation via API
Token Validation
Age token validation via AgeOnce API.
Endpoint
POST https://app.ageonce.com/api/oauth/validateRequest
Headers
Content-Type: application/jsonBody
{
"token": "eyJhbGciOiJSUzI1NiIs..."
}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
token | string | Yes | Age token to validate |
Response
Valid token (200)
{
"valid": true,
"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": "cl_abc123",
"iat": 1739275200,
"exp": 1739361600,
"iss": "ageonce"
}
}The verification_id in the payload is the Transaction ID (same as transaction_id from token exchange). Store it if you need to track when and how access was granted; you can search by this ID in Dashboard Audit Logs for compliance and support.
Invalid token (200)
{
"valid": false,
"error": "Token has expired"
}Note: invalid token returns HTTP 200 but with valid: false.
Possible errors
| Error | Description |
|---|---|
Token has expired | Token expired |
Invalid signature | Invalid token signature |
Invalid issuer | Invalid issuer |
Malformed token | Malformed token format |
Examples
curl -X POST https://app.ageonce.com/api/oauth/validate \
-H "Content-Type: application/json" \
-d '{
"token": "eyJhbGciOiJSUzI1NiIs..."
}'async function validateToken(token) {
const response = await fetch('https://app.ageonce.com/api/oauth/validate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ token }),
});
const data = await response.json();
if (data.valid && data.payload.age_verified) {
console.log('User age verified:', data.payload.min_age);
return true;
}
console.log('Validation failed:', data.error);
return false;
}import requests
def validate_token(token):
response = requests.post(
'https://app.ageonce.com/api/oauth/validate',
json={'token': token}
)
data = response.json()
if data.get('valid') and data.get('payload', {}).get('age_verified'):
print(f"User age verified: {data['payload']['min_age']}")
return True
print(f"Validation failed: {data.get('error')}")
return Falsefunction validateToken($token) {
$response = file_get_contents('https://app.ageonce.com/api/oauth/validate', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/json',
'content' => json_encode(['token' => $token]),
],
]));
$data = json_decode($response, true);
if ($data['valid'] && $data['payload']['age_verified']) {
echo "User age verified: " . $data['payload']['min_age'];
return true;
}
echo "Validation failed: " . ($data['error'] ?? 'Unknown error');
return false;
}API vs Local Validation
| Aspect | API validation | Local validation |
|---|---|---|
| Speed | Slower (HTTP request) | Faster |
| Simplicity | Simpler | Requires JWKS |
| Reliability | Always up-to-date key | Need to cache keys |
| Offline | Doesn't work | Works |
For high-load systems, we recommend local validation with JWKS caching.
Local validation
For local validation, use the JWKS endpoint to get the public key.
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');
const client = jwksClient({
jwksUri: 'https://app.ageonce.com/api/oauth/jwks',
cache: true,
cacheMaxAge: 86400000, // 24 hours
});
function getKey(header, callback) {
client.getSigningKey(header.kid, (err, key) => {
callback(null, key.publicKey || key.rsaPublicKey);
});
}
jwt.verify(token, getKey, { algorithms: ['RS256'], issuer: 'ageonce' }, (err, decoded) => {
if (err) {
console.log('Invalid token:', err.message);
} else {
console.log('Valid token:', decoded);
}
});