Skip to content

JWT Tokens

JSON Web Tokens (JWT) are the access tokens returned by Sesamy's Auth0-compatible authentication system. They provide stateless authentication for your API requests.

Overview

JWTs are compact, URL-safe tokens that contain encoded claims about a user or service. Sesamy issues JWTs as access tokens when you complete an authentication flow.

JWT Structure

A JWT consists of three parts separated by dots (.):

header.payload.signature

Example:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImF6cCI6ImNsaWVudF9pZCIsImV4cCI6MTY5ODg1ODgwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Contains token type and signing algorithm:

json
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "key_id"
}

Sesamy uses RS256 (RSA) for signing, which means you can verify tokens using Sesamy's public key.

Payload

Contains claims (user or service data):

json
{
  "sub": "user_123",
  "aud": "https://api.sesamy.com",
  "vendor_id": "vendor_456",
  "iss": "https://token.sesamy.com/",
  "exp": 1698858800,
  "iat": 1698855200,
  "email": "user@example.com",
  "email_verified": true
}

Signature

Cryptographically signed with Sesamy's private key to verify authenticity and integrity.

Obtaining a JWT

Via Authorization Code Flow

After completing an OAuth authorization code flow, you'll receive a JWT access token:

bash
curl -X POST https://token.sesamy.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTHORIZATION_CODE" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "code_verifier=CODE_VERIFIER" \
  -d "redirect_uri=https://yourapp.com/callback"

Response:

json
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "refresh_token_value"
}

Via Refresh Token

When your access token expires, use the refresh token to obtain a new JWT:

bash
curl -X POST https://token.sesamy.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "refresh_token=REFRESH_TOKEN"

Via Client Credentials Flow

For Management API access, you'll receive a JWT using client credentials:

bash
curl -X POST https://token.sesamy.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "audience=https://api.sesamy.com"

Using JWT Tokens

Include the JWT in the Authorization header of your API requests:

bash
curl -X GET https://api.sesamy.com/client/v1/profile \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

SDK Examples

Since Sesamy uses Auth0-compatible authentication, you can use any Auth0-compatible SDK:

typescript
import { useAuth0 } from '@auth0/auth0-react';
import { useEffect, useState } from 'react';

function ProfileComponent() {
  const { getAccessTokenSilently } = useAuth0();
  const [profile, setProfile] = useState(null);

  useEffect(() => {
    const getProfile = async () => {
      const token = await getAccessTokenSilently({
        audience: 'https://api.sesamy.com',
        scope: 'openid profile email'
      });

      const response = await fetch('https://api.sesamy.com/client/v1/profile', {
        headers: { Authorization: `Bearer ${token}` }
      });

      setProfile(await response.json());
    };

    getProfile();
  }, []);

  return <div>{profile && <pre>{JSON.stringify(profile, null, 2)}</pre>}</div>;
}
python
from auth0.authentication import GetToken

# Get token for Management API
get_token = GetToken('auth.sesamy.com')
token = get_token.client_credentials(
    client_id='YOUR_CLIENT_ID',
    client_secret='YOUR_CLIENT_SECRET',
    audience='https://api.sesamy.com'
)

# Use token for API requests
import requests
headers = {'Authorization': f"Bearer {token['access_token']}"}
response = requests.get(
    'https://api.sesamy.com/management/v1/publishers',
    headers=headers
)

Token Claims

Sesamy JWTs include these standard OpenID Connect claims:

ClaimDescription
subSubject (unique user/service identifier)
issIssuer (https://token.sesamy.com/)
audAudience (https://api.sesamy.com for API access)
vendor_idYour vendor/publisher identifier
expExpiration time (Unix timestamp)
iatIssued at (Unix timestamp)
emailUser's email address
email_verifiedWhether email is verified
given_nameUser's first name
family_nameUser's last name

Validating JWTs

Server-Side Validation

Always validate JWTs on your server to ensure they're authentic:

  1. Verify Signature: Ensure the token is signed with Sesamy's key
  2. Check Expiration: Verify the exp claim hasn't passed
  3. Validate Issuer: Ensure iss is https://token.sesamy.com/
  4. Validate Audience: Ensure aud is https://api.sesamy.com
  5. Check Vendor ID: Ensure vendor_id claim matches your vendor identifier

Sesamy uses RS256 (RSA) signing, so you'll need to fetch the public key from the JWKS endpoint:

bash
curl https://token.sesamy.com/.well-known/jwks.json
typescript
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';

const client = jwksClient({
  jwksUri: 'https://token.sesamy.com/.well-known/jwks.json',
});

function getKey(header: any, callback: any) {
  client.getSigningKey(header.kid, (err, key) => {
    if (err) callback(err);
    callback(null, key?.getPublicKey());
  });
}

function validateToken(token: string) {
  return new Promise((resolve, reject) => {
    jwt.verify(
      token,
      getKey,
      {
        algorithms: ['RS256'],
        issuer: 'https://token.sesamy.com/',
        audience: 'https://api.sesamy.com',
      },
      (err, decoded) => {
        if (err) reject(err);
        resolve(decoded);
      }
    );
  });
}
python
import jwt
from functools import lru_cache

@lru_cache(maxsize=1)
def get_jwks():
    import requests
    return requests.get('https://token.sesamy.com/.well-known/jwks.json').json()

def validate_token(token: str):
import json

    # Get the key ID from token header
    unverified_header = jwt.get_unverified_header(token)
    kid = unverified_header.get('kid')

    # Get public key
    jwks = get_jwks()
    key = next((k for k in jwks['keys'] if k['kid'] == kid), None)

    if not key:
        raise ValueError('Key not found')

    # Construct public key
    from cryptography.hazmat.primitives import serialization
    from jwcrypto import jwk

    key_obj = jwk.JWK.from_json(json.dumps(key))
    public_key = key_obj.serialize(private_key=False, as_dict=False)

    # Verify token
    try:
        decoded = jwt.decode(
            token,
            public_key,
            algorithms=['RS256'],
            issuer='https://token.sesamy.com/',
            audience='https://api.sesamy.com'
        )
        return decoded
    except jwt.InvalidTokenError as e:
        raise ValueError(f'Invalid token: {e}')

Common Validation Issues

  • "Invalid signature": Check that you're using the current public key from JWKS endpoint
  • "Token expired": Use refresh tokens to obtain new access tokens
  • "Invalid issuer": Verify issuer is https://token.sesamy.com/
  • "Invalid audience": Verify audience is https://api.sesamy.com
  • "Invalid vendor_id": Ensure the vendor_id claim matches your vendor identifier

Token Refresh

When your JWT expires (typically after 1 hour), obtain a new one using your refresh token:

bash
curl -X POST https://token.sesamy.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "refresh_token=REFRESH_TOKEN"

Best Practices

  1. Always validate on backend: Never trust tokens without validation
  2. Store securely: Use httpOnly, secure cookies or localStorage (with caution)
  3. Use refresh tokens: Implement automatic token refresh before expiration
  4. Never expose JWTs in URLs or logs: Keep tokens private
  5. Use HTTPS for all token transmission: Prevent interception

Security Considerations

Security

  • Never expose JWTs in URLs or logs
  • Always validate tokens on the server
  • Use HTTPS for all token transmission
  • Implement CSRF protection
  • Rotate refresh tokens on use

Troubleshooting

Token Expired

Check the exp claim and refresh the token:

typescript
const decoded = jwt.decode(token);
if (decoded.exp * 1000 < Date.now()) {
  // Token expired, refresh it
  await refreshToken();
}

Invalid Signature

  • Verify you're using the correct public key
  • Ensure the token hasn't been tampered with
  • Check token isn't corrupted during transmission

Invalid Audience or Vendor ID

  • Ensure the JWT's aud claim is https://api.sesamy.com
  • Ensure the JWT's vendor_id claim matches your vendor identifier

Next Steps

Released under the MIT License.