Token Management
Learn about access tokens, refresh tokens, and token lifecycle management.
Token Types
Access Token
| Property | Description |
|---|---|
| Purpose | Authorize API requests |
| Format | JWT (JSON Web Token) |
| Lifetime | 1 hour (configurable) |
| Usage | Authorization: Bearer <token> |
Refresh Token
| Property | Description |
|---|---|
| Purpose | Obtain new access tokens |
| Format | Opaque string |
| Lifetime | 30 days (configurable) |
| Usage | Exchange for new access token |
ID Token
| Property | Description |
|---|---|
| Purpose | Contains user identity claims |
| Format | JWT |
| Lifetime | Same as access token |
| Usage | Retrieve user information |
Token Response
When you exchange an authorization code for tokens:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def50200a1b2c3d4e5f6...",
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"scope": "openid profile email"
}
Access Token Claims
Decoded JWT payload:
{
"iss": "https://api.syauth.com/e/v1",
"sub": "user-uuid",
"aud": "your-client-id",
"exp": 1703123456,
"iat": 1703119856,
"scope": "openid profile email",
"email": "[email protected]"
}
| Claim | Description |
|---|---|
iss | Token issuer (SyAuth) |
sub | Subject (user ID) |
aud | Audience (your client ID) |
exp | Expiration timestamp |
iat | Issued at timestamp |
scope | Granted scopes |
Refreshing Tokens
Access tokens are short-lived (usually 1 hour). When they expire, use the refresh token to get a new one.
- Next.js SDK/Frontend
- Manual / API
- Python
The SDK automatically handles token refreshing in the background before the access token expires.
const { getAccessToken } = useSyAuth();
// This function guarantees a valid token, refreshing if necessary
const token = await getAccessToken();
Make a POST request to the token endpoint:
curl -X POST https://api.syauth.com/e/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=YOUR_REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" # If using a Confidential Client
Note: If Token Rotation is enabled, you will receive a new refresh token in the response. You must use the new one for the next request.
import requests
response = requests.post("https://api.syauth.com/e/v1/oauth/token", data={
"grant_type": "refresh_token",
"refresh_token": "YOUR_REFRESH_TOKEN",
"client_id": "YOUR_CLIENT_ID",
# "client_secret": "YOUR_SECRET" # Optional
})
tokens = response.json()
print(tokens['access_token'])
Token Revocation
When a user logs out, you should revoke their tokens.
- Manual / API
- SDK
curl -X POST https://api.syauth.com/e/v1/oauth/revoke \
-d "token=TOKEN_TO_REVOKE" \
-d "token_type_hint=access_token" \
-d "client_id=YOUR_CLIENT_ID"
Calling logout() automatically clears tokens from the client.
Token Storage
Recommended: HttpOnly Cookies
The SDK stores tokens in secure HttpOnly cookies:
| Cookie | Flags |
|---|---|
syauth_access_token | HttpOnly, Secure, SameSite=Lax |
syauth_refresh_token | HttpOnly, Secure, SameSite=Lax |
Not Recommended: localStorage
Never store tokens in localStorage because:
- Accessible to JavaScript (XSS vulnerable)
- Persists across browser sessions
- No expiration control
Token Validation
You can validate tokens by calling the allowed-methods endpoint or by verifying the JWT signature locally.
- Remote Validation (Easiest)
- Local Validation (Node.js)
- Local Validation (Python)
Simply verify the token by using it to fetch user info. If the token is invalid, this will return 401.
curl https://api.syauth.com/e/v1/oauth/userinfo \
-H "Authorization: Bearer <access_token>"
For better performance, validate the JWT signature locally using the public key.
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
const client = jwksClient({
jwksUri: 'https://api.syauth.com/e/v1/.well-known/jwks.json'
});
function getKey(header, callback){
client.getSigningKey(header.kid, function(err, key) {
var signingKey = key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
});
}
jwt.verify(token, getKey, {}, function(err, decoded) {
console.log(decoded);
});
import jwt
from jwt import PyJWKClient
url = "https://api.syauth.com/e/v1/.well-known/jwks.json"
jwks_client = PyJWKClient(url)
signing_key = jwks_client.get_signing_key_from_jwt(token)
data = jwt.decode(
token,
signing_key.key,
algorithms=["RS256"],
audience="YOUR_CLIENT_ID",
issuer="https://api.syauth.com/e/v1"
)
Token Expiration Handling
SDK Automatic Handling
The SDK handles expiration automatically:
- Monitors token expiration
- Refreshes 5 minutes before expiry
- Seamlessly updates stored tokens
- Re-authenticates if refresh fails
Custom Handling
function MyComponent() {
const { getAccessToken, isAuthenticated } = useSyAuth();
const fetchData = async () => {
// getAccessToken() returns valid token or refreshes if needed
const token = await getAccessToken();
const response = await fetch('/api/data', {
headers: {
'Authorization': `Bearer ${token}`
}
});
return response.json();
};
}
Security Considerations
| Risk | Mitigation |
|---|---|
| Token theft | Use HttpOnly cookies, short expiration |
| Token replay | Validate audience and issuer claims |
| Refresh token abuse | Token rotation on use |
| XSS attacks | Never expose tokens to JavaScript |
Next Steps
- Session Handling - Manage user sessions
- Token Security - Security deep dive