Skip to main content

Data Token Verification

How to verify and validate data tokens for security.

Token Verification

Data tokens are JWTs that must be verified before use:

from sva_oauth_client.utils import get_sva_claims

# Token is automatically verified
claims = get_sva_claims(request)

Verification Process

1. Signature Verification

The token signature is verified using the secret key:

import jwt

decoded = jwt.decode(
data_token,
DATA_TOKEN_SECRET,
algorithms=['HS256'],
options={
"verify_signature": True,
}
)

2. Expiration Verification

The token expiration is checked:

decoded = jwt.decode(
data_token,
DATA_TOKEN_SECRET,
algorithms=['HS256'],
options={
"verify_exp": True,
}
)

3. Audience Verification (Optional)

The audience claim can be verified:

decoded = jwt.decode(
data_token,
DATA_TOKEN_SECRET,
algorithms=['HS256'],
audience=CLIENT_ID, # Verify audience
options={
"verify_signature": True,
"verify_exp": True,
}
)

Automatic Verification

The get_sva_claims() function automatically verifies:

  • Token signature
  • Token expiration
  • Token structure
from sva_oauth_client.utils import get_sva_claims
from sva_oauth_client.client import SVATokenError

try:
claims = get_sva_claims(request)
# Token is verified and valid
except SVATokenError:
# Token is invalid or expired
pass

Manual Verification

Verify Token Manually

from sva_oauth_client.client import get_client_from_settings
from sva_oauth_client.utils import get_data_token

def verify_token_manually(request):
"""Manually verify data token"""
data_token = get_data_token(request.session)

if not data_token:
return None

try:
client = get_client_from_settings()
decoded = client.decode_data_token(data_token)
return decoded
except SVATokenError:
return None

Token Structure Validation

Required Claims

Data tokens must contain:

  • sub - Subject (user ID)
  • aud - Audience (client ID)
  • auth_request_id - Authorization request ID
  • claims - User identity claims
  • exp - Expiration time
  • iat - Issued at time

Validate Structure

def validate_token_structure(decoded):
"""Validate token has required structure"""
required_claims = ['sub', 'aud', 'auth_request_id', 'claims', 'exp', 'iat']

for claim in required_claims:
if claim not in decoded:
raise ValueError(f"Missing required claim: {claim}")

if not isinstance(decoded['claims'], dict):
raise ValueError("Claims must be a dictionary")

return True

Security Checks

Signature Verification

Always verify the signature:

# ✅ Good - Verifies signature
decoded = jwt.decode(token, secret, algorithms=['HS256'])

# ❌ Bad - Doesn't verify signature
decoded = jwt.decode(token, options={"verify_signature": False})

Expiration Check

Always check expiration:

# ✅ Good - Checks expiration
decoded = jwt.decode(token, secret, algorithms=['HS256'])

# ❌ Bad - Doesn't check expiration
decoded = jwt.decode(token, secret, algorithms=['HS256'], options={"verify_exp": False})

Audience Validation

Validate audience matches your client:

# ✅ Good - Validates audience
decoded = jwt.decode(
token,
secret,
algorithms=['HS256'],
audience=CLIENT_ID
)

# ⚠️ Acceptable - Audience validation disabled (package default)
# The package disables audience validation by default
# because the audience may not match client_id in all cases

Error Handling

Invalid Token

from sva_oauth_client.client import SVATokenError

try:
claims = get_sva_claims(request)
except SVATokenError as e:
# Token is invalid
logger.warning(f"Invalid token: {e}")
# Handle error

Expired Token

from sva_oauth_client.client import SVATokenError
import jwt

try:
claims = get_sva_claims(request)
except jwt.ExpiredSignatureError:
# Token expired
logger.warning("Token expired")
# Handle expiration
except SVATokenError:
# Other token errors
pass

Best Practices

  1. Always verify - Never trust unverified tokens
  2. Check expiration - Tokens expire quickly (5 minutes)
  3. Validate structure - Ensure token has required claims
  4. Handle errors - Implement proper error handling
  5. Log failures - Monitor token verification failures

Configuration

Secret Key

# settings.py
SVA_DATA_TOKEN_SECRET = 'your-secret-key'

Important: Must match the secret configured in your SVA provider.

Algorithm

# settings.py
SVA_DATA_TOKEN_ALGORITHM = 'HS256' # or 'RS256'

Next Steps