Skip to content

Auth0 Authentication API — Programmatic Login and User Management

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Auth0 Authentication API. We cover key concepts, practical examples, and best practices to help you master this topic.

The Auth0 Authentication API provides programmatic access to authenticate users, exchange authorization codes for tokens, handle refresh tokens, manage user profiles, and query user information.

What You'll Learn

By the end of this lesson you will use the Authentication API endpoints to implement custom login flows, handle token exchange and refresh, fetch user profiles, and manage sessions.

Why It Matters

The Authentication API gives you full control over the auth flow for server-side applications, custom login UIs, and backend services where Universal Login's redirect flow is not suitable.

Real-World Use

DodaZIP uses the Authentication API for server-side token validation. When a backend service receives a request, it calls the /userinfo endpoint to verify the token is valid and fetch the user's profile.

flowchart LR
    A[Client App] -->|Authorization Code| B[Auth0 /oauth/token]
    B -->|Access Token| A
    A -->|API Call| C[Backend Service]
    C -->|Validate Token| D[Auth0 /userinfo]
    D -->|User Profile| C
    style B fill:#eb5424,color:#fff

Authentication Endpoints

Key endpoints for programmatic authentication.

# auth_endpoints.py
# Key Authentication API endpoints

def auth_api_endpoints():
    endpoints = {
        "/authorize": "Initiates the authentication flow, redirects to login",
        "/oauth/token": "Exchanges authorization code for tokens",
        "/oauth/token": "Also used for refresh token and client credentials",
        "/userinfo": "Returns user profile for a valid access token",
        "/dbconnections/signup": "Creates a new user in the database connection",
        "/dbconnections/change_password": "Triggers password change email",
        "/passwordless/start": "Starts passwordless authentication",
        "/users/{id}": "Fetches or updates a specific user profile",
    }
    
    print("Authentication API Endpoints:")
    for endpoint, desc in endpoints.items():
        print(f"  {endpoint:45s} {desc}")

auth_api_endpoints()

Token Exchange

Exchange an authorization code for tokens.

# POST /oauth/token
curl --request POST \
  --url 'https://YOUR_TENANT.us.auth0.com/oauth/token' \
  --header 'content-type: application/json' \
  --data '{
    "grant_type": "authorization_code",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "code": "AUTHORIZATION_CODE",
    "redirect_uri": "https://yourapp.com/callback"
  }'
# token_exchange.py
# Exchange authorization code for tokens

import requests
import os

def exchange_code(auth_code):
    domain = os.getenv("AUTH0_DOMAIN", "your-tenant.us.auth0.com")
    client_id = os.getenv("AUTH0_CLIENT_ID", "your-client-id")
    client_secret = os.getenv("AUTH0_CLIENT_SECRET", "your-client-secret")
    
    response = requests.post(
        f"https://{domain}/oauth/token",
        json={
            "grant_type": "authorization_code",
            "client_id": client_id,
            "client_secret": client_secret,
            "code": auth_code,
            "redirect_uri": "https://dodatech.app/callback",
        }
    )
    
    if response.status_code == 200:
        tokens = response.json()
        print("Token exchange successful")
        print(f"  Access token: {tokens['access_token'][:20]}...")
        print(f"  ID token: {tokens.get('id_token', 'N/A')[:20]}...")
        print(f"  Expires in: {tokens['expires_in']} seconds")
        if "refresh_token" in tokens:
            print(f"  Refresh token: {tokens['refresh_token'][:20]}...")
        return tokens
    else:
        print(f"Token exchange failed: {response.text}")
        return None

exchange_code("sample_auth_code_123")

Refreshing Tokens

Use refresh tokens to maintain sessions.

# refresh_token.py
# Session management with refresh tokens

def refresh_session(refresh_token):
    domain = os.getenv("AUTH0_DOMAIN", "your-tenant.us.auth0.com")
    client_id = os.getenv("AUTH0_CLIENT_ID", "your-client-id")
    client_secret = os.getenv("AUTH0_CLIENT_SECRET", "your-client-secret")
    
    response = requests.post(
        f"https://{domain}/oauth/token",
        json={
            "grant_type": "refresh_token",
            "client_id": client_id,
            "client_secret": client_secret,
            "refresh_token": refresh_token,
        }
    )
    
    if response.status_code == 200:
        tokens = response.json()
        print("Session refreshed")
        print(f"  New access token: {tokens['access_token'][:20]}...")
        print(f"  New refresh token: {tokens.get('refresh_token', 'N/A')[:20]}...")
        return tokens
    else:
        print(f"Refresh failed: {response.text}")
        return None

refresh_session("sample_refresh_token_123")

User Profile

Fetch user profile information with the access token.

# user_profile.py
# Fetch user profile

def get_user_profile(access_token):
    domain = os.getenv("AUTH0_DOMAIN", "your-tenant.us.auth0.com")
    
    response = requests.get(
        f"https://{domain}/userinfo",
        headers={"Authorization": f"Bearer {access_token}"}
    )
    
    if response.status_code == 200:
        profile = response.json()
        print("User Profile:")
        print(f"  Sub (ID): {profile.get('sub')}")
        print(f"  Name: {profile.get('name')}")
        print(f"  Email: {profile.get('email')}")
        print(f"  Email verified: {profile.get('email_verified')}")
        print(f"  Picture: {profile.get('picture')}")
        return profile
    else:
        print(f"Failed to get profile: {response.text}")
        return None

get_user_profile("sample_access_token_123")

Common Mistakes

  1. Not validating tokens on the server: Always validate tokens (signature, expiry, audience) on your backend. Trusting unvalidated tokens is a critical vulnerability.

  2. Storing refresh tokens in localStorage: Refresh tokens should be stored in httpOnly cookies, not accessible to JavaScript, to prevent XSS Attacks.

  3. Exchanging the authorization code multiple times: An authorization code is single-use. Attempting to reuse it returns an error.

  4. Not using PKCE for public clients: SPAs and mobile apps should use PKCE to prevent authorization code interception attacks.

  5. Forgetting to handle token expiry: Access tokens expire. Implement automatic token refresh in your client or redirect to login when expired.

Practice Questions

  1. What is the /oauth/token endpoint used for? Exchanging authorization codes, refresh tokens, and client credentials for access tokens.

  2. How do you refresh an expired access token? POST to /oauth/token with grant_type=refresh_token and the refresh token.

  3. What does the /userinfo endpoint return? The user's profile information including sub, name, email, and picture.

  4. Why should you validate tokens on the server? To verify the token signature, check expiration, and ensure the audience matches your API.

  5. Challenge: Create a Python script that performs a complete authentication flow: exchange a code for tokens, fetch the user profile, and handle token refresh.

FAQ

Can I use the Authentication API from a mobile app?

Yes. Mobile apps use the same API with PKCE for security. Native SDKs handle this automatically.

How long does an access token last?

The default is 86400 seconds (24 hours). You can configure this in Tenant Settings.

What is the difference between access token and ID token?

Access token authorizes API access. ID token contains user profile claims.

Can I call the Authentication API without a client secret?

Yes, with PKCE. Public clients (SPAs, mobile) use a code verifier instead of a client secret.

What scopes should I request?

Request the minimum: openid (required), profile, email. Additional scopes add claims to the ID token.

Mini Project

Create a token management service that stores tokens securely, handles automatic refresh, and provides a getValidToken() method that always returns a fresh access token.

class TokenManager:
    def __init__(self, domain, client_id, client_secret):
        self.domain = domain
        self.client_id = client_id
        self.client_secret = client_secret
        self.access_token = None
        self.refresh_token = None
        self.expires_at = 0
    
    async def get_valid_token(self):
        import time
        if time.time() >= self.expires_at and self.refresh_token:
            await self.refresh()
        return self.access_token
    
    async def refresh(self):
        response = requests.post(
            f"https://{self.domain}/oauth/token",
            json={
                "grant_type": "refresh_token",
                "client_id": self.client_id,
                "client_secret": self.client_secret,
                "refresh_token": self.refresh_token,
            }
        )
        data = response.json()
        self.access_token = data["access_token"]
        self.expires_at = __import__("time").time() + data["expires_in"]

manager = TokenManager("tenant.us.auth0.com", "client_id", "client_secret")
print(f"Token manager initialized with domain: {manager.domain}")

What's Next

Next: Social Connections for social login.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro