Authentication Guide

Updated: May 12, 2025 Reading time: 12 min

Introduction to API Authentication

Authentication is the process of verifying the identity of a client or user attempting to access the API. It ensures that only authorized parties can access your resources and perform operations. MyAppAPI supports multiple authentication methods to accommodate different security requirements and use cases.

Authentication vs. Authorization

Authentication verifies who you are, while authorization determines what you can do. This guide focuses on authentication. For information on roles, permissions, and access control, see our Authorization Guide.

Choosing the Right Authentication Method

MyAppAPI offers several authentication methods, each with its own advantages and use cases:

Method Best For Security Level Complexity
API Keys Server-to-server, scripts, backend services Medium Low
OAuth 2.0 User-context operations, third-party integrations High High
JWT Stateless authentication, microservices High Medium
Session Tokens Web applications, frontend clients Medium Low

The following sections provide detailed information about each authentication method, with implementation examples for various programming languages and frameworks.

API Keys

API keys are simple, long-lived tokens that identify your application or project when making API requests. They are the simplest authentication method and are ideal for server-to-server communications and backend services.

Getting Your API Key

To get an API key:

  1. Log in to the MyAppAPI Dashboard
  2. Navigate to SettingsAPI Keys
  3. Click Create New API Key
  4. Name your key and set appropriate permissions
  5. Copy and securely store your API key

Important

Your API key is displayed only once when created. If you lose it, you'll need to generate a new one. Store it securely and never expose it in client-side code or public repositories.

Using API Keys

There are two ways to include your API key in requests:

1. HTTP Header (Recommended)

Include your API key in the X-API-Key header:

curl -X GET "https://api.myappapi.com/v1/users" \
  -H "X-API-Key: your_api_key_here"
// Using Fetch API
fetch('https://api.myappapi.com/v1/users', {
  headers: {
    'X-API-Key': 'your_api_key_here'
  }
})
.then(response => response.json())
.then(data => console.log(data));

// Using Axios
const axios = require('axios');

axios.get('https://api.myappapi.com/v1/users', {
  headers: {
    'X-API-Key': 'your_api_key_here'
  }
})
.then(response => console.log(response.data));
import requests

headers = {
    'X-API-Key': 'your_api_key_here'
}

response = requests.get('https://api.myappapi.com/v1/users', headers=headers)
data = response.json()
print(data)
<?php
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.myappapi.com/v1/users');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: your_api_key_here'
]);

$response = curl_exec($ch);
$data = json_decode($response, true);

curl_close($ch);
?>

2. Query Parameter (Less Secure)

You can also include your API key as a query parameter, though this is less secure because API keys in URLs may be logged:

GET https://api.myappapi.com/v1/users?api_key=your_api_key_here

Security Note

Query parameter authentication should only be used for development or when HTTP headers aren't available. Never use this method for production applications.

API Key Management

Best practices for managing API keys:

  • Create multiple keys for different environments (development, staging, production)
  • Name keys descriptively to track their usage (e.g., "Production Backend Service")
  • Rotate keys periodically to limit the impact of potential breaches
  • Revoke unused keys to reduce your attack surface
  • Store keys securely using environment variables or secrets management tools
  • Monitor key usage to detect unauthorized access

For additional security, you can restrict API keys to specific IP addresses or referrer domains in the API key settings.

OAuth 2.0 Authentication

OAuth 2.0 is an industry-standard protocol for authorization that enables secure, delegated access to APIs. It's ideal for applications that need to access resources on behalf of users without handling their credentials directly.

OAuth 2.0 Flow Types

MyAppAPI supports the following OAuth 2.0 flows:

Flow Best For Description
Authorization Code Web applications Server-side flow with callback URL, most secure option
Authorization Code with PKCE Mobile/native apps Enhanced security for public clients without client secrets
Implicit Single-page applications Frontend-only flow that returns tokens directly (less secure)
Client Credentials Server-to-server Machine-to-machine authentication without user context

Setting Up OAuth

To implement OAuth 2.0 authentication:

  1. Register your application in the MyAppAPI Dashboard
  2. Configure redirect URLs and select the required scopes
  3. Receive your Client ID and Client Secret
  4. Implement the appropriate OAuth flow in your application

OAuth Endpoints

Endpoint URL Purpose
Authorization https://auth.myappapi.com/oauth/authorize Initiates user authentication and consent
Token https://auth.myappapi.com/oauth/token Exchanges authorization codes for tokens
Revocation https://auth.myappapi.com/oauth/revoke Revokes active tokens
User Info https://auth.myappapi.com/oauth/userinfo Retrieves authenticated user information

Authorization Code Flow Example

This is the most common and secure OAuth flow for web applications:

Step 1: Redirect to Authorization Page

// Construct the authorization URL
const authorizationUrl = new URL('https://auth.myappapi.com/oauth/authorize');
authorizationUrl.searchParams.append('client_id', 'YOUR_CLIENT_ID');
authorizationUrl.searchParams.append('redirect_uri', 'https://yourapp.com/callback');
authorizationUrl.searchParams.append('response_type', 'code');
authorizationUrl.searchParams.append('scope', 'read:users write:users');
authorizationUrl.searchParams.append('state', generateRandomState()); // Security measure

// Redirect the user
window.location.href = authorizationUrl.toString();
<?php
// Construct the authorization URL
$params = [
    'client_id' => 'YOUR_CLIENT_ID',
    'redirect_uri' => 'https://yourapp.com/callback',
    'response_type' => 'code',
    'scope' => 'read:users write:users',
    'state' => bin2hex(random_bytes(16)) // Security measure
];

// Store state in session for verification
$_SESSION['oauth_state'] = $params['state'];

// Redirect the user
$authUrl = 'https://auth.myappapi.com/oauth/authorize?' . http_build_query($params);
header('Location: ' . $authUrl);
exit;
?>

Step 2: Handle the Callback

// Using Express.js as an example
app.get('/callback', async (req, res) => {
    // Verify state to prevent CSRF
    if (req.query.state !== storedState) {
        return res.status(400).send('State mismatch error');
    }
    
    // Exchange code for tokens
    try {
        const tokenResponse = await fetch('https://auth.myappapi.com/oauth/token', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: new URLSearchParams({
                client_id: 'YOUR_CLIENT_ID',
                client_secret: 'YOUR_CLIENT_SECRET',
                grant_type: 'authorization_code',
                code: req.query.code,
                redirect_uri: 'https://yourapp.com/callback'
            })
        });
        
        const tokens = await tokenResponse.json();
        
        // Store tokens securely (e.g., in encrypted session/database)
        req.session.accessToken = tokens.access_token;
        req.session.refreshToken = tokens.refresh_token;
        
        // Redirect to app home
        res.redirect('/dashboard');
    } catch (error) {
        console.error('Error exchanging code for tokens:', error);
        res.status(500).send('Authentication failed');
    }
});
<?php
// Callback handler
session_start();

// Verify state to prevent CSRF
if ($_GET['state'] !== $_SESSION['oauth_state']) {
    die('State mismatch error');
}

// Exchange code for tokens
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://auth.myappapi.com/oauth/token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'client_id' => 'YOUR_CLIENT_ID',
    'client_secret' => 'YOUR_CLIENT_SECRET',
    'grant_type' => 'authorization_code',
    'code' => $_GET['code'],
    'redirect_uri' => 'https://yourapp.com/callback'
]));

$response = curl_exec($ch);
$tokens = json_decode($response, true);
curl_close($ch);

if (isset($tokens['access_token'])) {
    // Store tokens securely
    $_SESSION['access_token'] = $tokens['access_token'];
    $_SESSION['refresh_token'] = $tokens['refresh_token'];
    
    // Redirect to app home
    header('Location: /dashboard');
    exit;
} else {
    // Handle error
    die('Authentication failed');
}
?>

Step 3: Use the Access Token

// Making authenticated API requests
async function getUserProfile() {
    try {
        const response = await fetch('https://api.myappapi.com/v1/users/me', {
            headers: {
                'Authorization': `Bearer ${accessToken}`
            }
        });
        
        return await response.json();
    } catch (error) {
        console.error('API request failed:', error);
        // Handle token expiration and refresh if needed
        if (error.status === 401) {
            await refreshAccessToken();
            return getUserProfile();
        }
        throw error;
    }
}
<?php
// Making authenticated API requests
function getUserProfile() {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://api.myappapi.com/v1/users/me');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $_SESSION['access_token']
    ]);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    // Handle token expiration
    if ($httpCode === 401) {
        refreshAccessToken();
        return getUserProfile();
    }
    
    return json_decode($response, true);
}
?>

Token Refresh Flow

OAuth access tokens expire after a set time (typically 1 hour). Use refresh tokens to get a new access token without user interaction:

async function refreshAccessToken() {
    try {
        const tokenResponse = await fetch('https://auth.myappapi.com/oauth/token', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: new URLSearchParams({
                client_id: 'YOUR_CLIENT_ID',
                client_secret: 'YOUR_CLIENT_SECRET',
                grant_type: 'refresh_token',
                refresh_token: refreshToken
            })
        });
        
        const tokens = await tokenResponse.json();
        
        // Update stored tokens
        accessToken = tokens.access_token;
        // Refresh token might also be updated
        if (tokens.refresh_token) {
            refreshToken = tokens.refresh_token;
        }
        
        return tokens;
    } catch (error) {
        console.error('Error refreshing token:', error);
        // If refresh fails, redirect to login
        window.location.href = '/login';
        throw error;
    }
}
import requests

def refresh_access_token(refresh_token):
    token_url = 'https://auth.myappapi.com/oauth/token'
    
    payload = {
        'client_id': 'YOUR_CLIENT_ID',
        'client_secret': 'YOUR_CLIENT_SECRET',
        'grant_type': 'refresh_token',
        'refresh_token': refresh_token
    }
    
    response = requests.post(token_url, data=payload)
    
    if response.status_code == 200:
        tokens = response.json()
        # Update stored tokens
        access_token = tokens['access_token']
        # Refresh token might also be updated
        if 'refresh_token' in tokens:
            refresh_token = tokens['refresh_token']
            
        return tokens
    else:
        # If refresh fails, redirect to login
        print('Token refresh failed, user must log in again')
        return None

OAuth Libraries

Consider using established OAuth libraries for your platform to simplify implementation and avoid security pitfalls:

JWT Authentication

JSON Web Tokens (JWT) provide a compact, self-contained way for securely transmitting information between parties. This makes them ideal for stateless authentication in distributed systems.

JWT Structure

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

  • Header: Contains token type and signing algorithm
  • Payload: Contains claims (user data and metadata)
  • Signature: Verifies the token's integrity
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsIm5hbWUiOiJKb2huIERvZSIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Obtaining JWT Tokens

There are two ways to obtain JWT tokens with MyAppAPI:

1. Via OAuth 2.0

When using OAuth flows, you can request JWT format tokens by adding token_format=jwt to your token request:

POST https://auth.myappapi.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=AuthorizationCodeFromCallback&
client_id=YourClientId&
client_secret=YourClientSecret&
redirect_uri=https://yourapp.com/callback&
token_format=jwt

2. Via Direct Authentication

For server-side applications, you can obtain a JWT by authenticating directly:

async function getJwtToken() {
    const response = await fetch('https://auth.myappapi.com/v1/auth/token', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            client_id: 'YOUR_CLIENT_ID',
            client_secret: 'YOUR_CLIENT_SECRET',
            audience: 'https://api.myappapi.com',
            grant_type: 'client_credentials'
        })
    });
    
    const data = await response.json();
    return data.access_token; // This is a JWT
}
import requests

def get_jwt_token():
    url = 'https://auth.myappapi.com/v1/auth/token'
    
    payload = {
        'client_id': 'YOUR_CLIENT_ID',
        'client_secret': 'YOUR_CLIENT_SECRET',
        'audience': 'https://api.myappapi.com',
        'grant_type': 'client_credentials'
    }
    
    response = requests.post(url, json=payload)
    data = response.json()
    
    return data['access_token']  # This is a JWT

Using JWT Tokens

Include the JWT in the Authorization header with the Bearer scheme:

curl -X GET "https://api.myappapi.com/v1/users" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
fetch('https://api.myappapi.com/v1/users', {
  headers: {
    'Authorization': `Bearer ${jwtToken}`
  }
})
.then(response => response.json())
.then(data => console.log(data));
import requests

headers = {
    'Authorization': f'Bearer {jwt_token}'
}

response = requests.get('https://api.myappapi.com/v1/users', headers=headers)
data = response.json()
print(data)

JWT Validation

JWTs should be validated on the client side to ensure they are not expired or tampered with:

// Using jose library
const { jwtVerify } = require('jose');

async function validateToken(token) {
    try {
        // Fetch public key (or use pre-shared secret)
        const JWKS = jose.createRemoteJWKSet(
            new URL('https://auth.myappapi.com/.well-known/jwks.json')
        );
        
        // Verify token
        const { payload } = await jwtVerify(token, JWKS, {
            issuer: 'https://auth.myappapi.com/',
            audience: 'https://api.myappapi.com'
        });
        
        // Check if token is expired
        const now = Math.floor(Date.now() / 1000);
        if (payload.exp < now) {
            throw new Error('Token expired');
        }
        
        return payload;
    } catch (error) {
        console.error('Token validation failed:', error);
        throw error;
    }
}
import jwt
import requests
from jwt.algorithms import RSAAlgorithm
import time

def validate_token(token):
    try:
        # Fetch public key
        jwks_url = 'https://auth.myappapi.com/.well-known/jwks.json'
        jwks_response = requests.get(jwks_url)
        jwks = jwks_response.json()
        
        # Extract key information from token header
        header = jwt.get_unverified_header(token)
        key = None
        
        for jwk in jwks['keys']:
            if jwk['kid'] == header['kid']:
                key = RSAAlgorithm.from_jwk(jwk)
                break
        
        if key is None:
            raise ValueError("Public key not found")
        
        # Verify token
        payload = jwt.decode(
            token,
            key,
            algorithms=['RS256'],
            options={"verify_signature": True},
            audience='https://api.myappapi.com',
            issuer='https://auth.myappapi.com/'
        )
        
        # Check if token is expired
        now = int(time.time())
        if payload['exp'] < now:
            raise jwt.ExpiredSignatureError("Token expired")
            
        return payload
    except Exception as e:
        print(f"Token validation failed: {e}")
        raise

JWT Security Considerations

When working with JWTs:

  • Always validate tokens on the server side
  • Use short expiration times for tokens (1 hour or less)
  • Implement token revocation for logout or security breaches
  • Never store sensitive information in JWT payloads
  • Use HTTPS to prevent token interception

Session Tokens

Session tokens provide a simpler authentication mechanism for web applications. They are typically used for frontend clients and browser-based applications.

Obtaining Session Tokens

To obtain a session token, users must authenticate through the login endpoint:

async function login(email, password) {
    const response = await fetch('https://auth.myappapi.com/v1/auth/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            email: email,
            password: password
        })
    });
    
    const data = await response.json();
    
    if (response.ok) {
        // Store the session token
        localStorage.setItem('sessionToken', data.session_token);
        return data;
    } else {
        throw new Error(data.message || 'Authentication failed');
    }
}
import requests

def login(email, password):
    url = 'https://auth.myappapi.com/v1/auth/login'
    
    payload = {
        'email': email,
        'password': password
    }
    
    response = requests.post(url, json=payload)
    data = response.json()
    
    if response.status_code == 200:
        # Store the session token
        session_token = data['session_token']
        return data
    else:
        raise Exception(data.get('message', 'Authentication failed'))

Using Session Tokens

Include the session token in the X-Session-Token header:

async function fetchUserProfile() {
    const sessionToken = localStorage.getItem('sessionToken');
    
    if (!sessionToken) {
        throw new Error('Not authenticated');
    }
    
    const response = await fetch('https://api.myappapi.com/v1/users/me', {
        headers: {
            'X-Session-Token': sessionToken
        }
    });
    
    if (response.status === 401) {
        // Token expired or invalid
        localStorage.removeItem('sessionToken');
        // Redirect to login
        window.location.href = '/login';
        return;
    }
    
    return await response.json();
}
import requests

def fetch_user_profile(session_token):
    if not session_token:
        raise Exception('Not authenticated')
    
    headers = {
        'X-Session-Token': session_token
    }
    
    response = requests.get('https://api.myappapi.com/v1/users/me', headers=headers)
    
    if response.status_code == 401:
        # Token expired or invalid
        print('Session expired, please log in again')
        return None
    
    return response.json()

Session Token Lifecycle

Session tokens typically have the following lifecycle:

  • Creation: Generated when the user successfully logs in
  • Expiration: Automatically expires after a set time (default: 24 hours)
  • Renewal: Can be refreshed using the renewal endpoint
  • Revocation: Explicitly invalidated when the user logs out

Renewing Session Tokens

async function renewSessionToken() {
    const currentToken = localStorage.getItem('sessionToken');
    
    if (!currentToken) {
        throw new Error('No session token to renew');
    }
    
    try {
        const response = await fetch('https://auth.myappapi.com/v1/auth/renew', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-Session-Token': currentToken
            }
        });
        
        const data = await response.json();
        
        if (response.ok) {
            // Update the session token
            localStorage.setItem('sessionToken', data.session_token);
            return data;
        } else {
            // Token couldn't be renewed
            localStorage.removeItem('sessionToken');
            throw new Error(data.message || 'Session renewal failed');
        }
    } catch (error) {
        console.error('Error renewing session:', error);
        // Redirect to login
        window.location.href = '/login';
        throw error;
    }
}

Logging Out (Revoking Session Tokens)

async function logout() {
    const sessionToken = localStorage.getItem('sessionToken');
    
    if (sessionToken) {
        try {
            // Revoke the token on the server
            await fetch('https://auth.myappapi.com/v1/auth/logout', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-Session-Token': sessionToken
                }
            });
        } catch (error) {
            console.error('Error during logout:', error);
        }
        
        // Always clear local storage even if server request fails
        localStorage.removeItem('sessionToken');
    }
    
    // Redirect to login
    window.location.href = '/login';
}

Session Security Tips

To ensure secure handling of session tokens:

  • Always use HTTPS to prevent token interception
  • Store tokens in secure, HTTP-only cookies when possible
  • Implement CSRF protection for cookie-based sessions
  • Use shorter expiration times for sensitive operations
  • Provide a "Remember Me" option to control session duration based on user preference

Security Best Practices

Implementing proper authentication is just the first step. Follow these security best practices to ensure your API integrations remain secure:

General Security Recommendations

  • Use HTTPS for all API requests to prevent man-in-the-middle attacks and data exposure
  • Implement proper error handling to avoid leaking sensitive information in error messages
  • Keep authentication credentials secure — never expose them in client-side code or GitHub repositories
  • Use environment variables or secure secrets management solutions to store API keys and secrets
  • Implement rate limiting on your side to avoid hitting API rate limits
  • Monitor API usage to detect unusual patterns that might indicate a breach

API Key Security

  • Never use API keys directly in client-side code — always proxy requests through your server
  • Rotate API keys regularly, especially after team member changes
  • Use scoped API keys with the minimum required permissions
  • Set IP restrictions on API keys when possible

OAuth Security

  • Use the Authorization Code flow with PKCE for mobile and SPA applications
  • Validate all redirect URIs to prevent open redirect vulnerabilities
  • Implement state parameter validation to prevent CSRF attacks
  • Request the minimum required scopes to limit potential security impact
  • Store refresh tokens securely on the server side, not in client-side storage

JWT Security

  • Always validate JWTs on the server side, checking signature, expiration, issuer, and audience
  • Use short expiration times for tokens to limit the window of vulnerability
  • Implement token revocation for logout or security breaches
  • Don't store sensitive information in JWT payloads, as they are easily decoded

Session Security

  • Use HTTP-only, secure cookies for web applications when possible
  • Implement CSRF protection for cookie-based sessions
  • Regenerate session IDs after authentication state changes
  • Set appropriate idle and absolute timeouts for sessions

Security Auditing

Regularly review your authentication implementation for security vulnerabilities. Consider using security tools like OWASP ZAP, automated scanners, or professional security audits for critical applications.

Troubleshooting Authentication Issues

If you encounter authentication problems, use this section to diagnose and resolve common issues:

Common Error Codes

HTTP Status Error Code Description Resolution
401 invalid_credentials API key or credentials are invalid Verify your API key or credentials are correct and active
401 expired_token Token has expired Refresh the token or re-authenticate
401 invalid_token Token signature verification failed Ensure the token hasn't been tampered with or incorrectly generated
403 insufficient_permissions User lacks permission for the requested action Request additional permissions or use an account with higher privileges
403 invalid_scope Token does not have the required scope Request the necessary scopes during OAuth authorization
429 rate_limit_exceeded Too many authentication attempts Implement exponential backoff and retry after the specified time

Debugging Tips

  • Check response headers: Authentication errors often include helpful information in response headers
  • Verify token format: Ensure you're correctly formatting your authorization headers (e.g., Bearer <token>)
  • Inspect token content: For JWTs, use tools like jwt.io to decode and inspect the contents
  • Check token expiration: Verify that your tokens haven't expired and that your system's clock is correctly synchronized
  • Examine scopes: Ensure your token has the necessary scopes for the requested operation
  • Test with curl: Use curl commands to isolate API issues from application code problems

Getting Help

If you've tried the troubleshooting steps and still encounter issues:

  • Check our FAQ for common questions and answers
  • Visit the MyAppAPI Community Forum to see if others have encountered similar issues
  • Contact [email protected] with details about your issue, including:
    • Authentication method you're using
    • Error messages and status codes
    • API endpoint you're trying to access
    • Code snippets demonstrating your authentication implementation (without sensitive credentials)