Skip to main content

User Registration

Before using the API, users must register through your organization’s registration page to obtain login credentials.

Get OAuth2 Token

Password Grant (Username/Password)

Endpoint
POST /auth/token
Headers
Content-Type: application/json
Request Body
{
  "username": "<Your User ID>",
  "password": "<Your Password>",
  "grant_type": "password"
}
Success Response (200 OK)
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "user",
  "user_level": "admin"
}
Response Fields
  • access_token: JWT token for API authentication
  • token_type: Always “Bearer”
  • expires_in: Token lifetime in seconds (3600 = 1 hour)
  • scope: User’s permission scope
  • user_level: Either “admin” or “user” based on account permissions

Client Credentials Grant

For server-to-server authentication: Request Body
{
  "grant_type": "client_credentials",
  "client_id": "<Your Client ID>",
  "client_secret": "<Your Client Secret>",
  "scope": "<Requested Scope>"
}

Authorization Code Grant

For web applications with user consent:
  1. Authorization Request
GET /auth/authorize?response_type=code&client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&scope=<SCOPE>
  1. Token Exchange
{
  "grant_type": "authorization_code",
  "code": "<Authorization Code>",
  "client_id": "<Your Client ID>",
  "client_secret": "<Your Client Secret>",
  "redirect_uri": "<Redirect URI>"
}

Using Access Tokens

Include the access token in the Authorization header for all API requests:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
Example API Request
curl -X GET "https://api.yourdomain.com/documents" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
  -H "Content-Type: application/json"

Token Management

Token Expiration

  • Access tokens expire after 1 hour (3600 seconds)
  • No refresh tokens are provided - re-authenticate using the same credentials
  • Monitor the expires_in field to proactively refresh tokens

Token Refresh Example

// JavaScript example for automatic token refresh
let tokenData = null;
let tokenExpiry = null;

async function getValidToken() {
  if (!tokenData || Date.now() >= tokenExpiry) {
    tokenData = await authenticate();
    tokenExpiry = Date.now() + (tokenData.expires_in * 1000);
  }
  return tokenData.access_token;
}

async function authenticate() {
  const response = await fetch('/auth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      username: 'your-username',
      password: 'your-password',
      grant_type: 'password'
    })
  });
  return await response.json();
}

Error Responses

Invalid Credentials (401 Unauthorized)

{
  "error": "invalid_grant",
  "error_description": "Invalid username or password"
}

Account Locked (423 Locked)

{
  "error": "account_locked",
  "error_description": "Account temporarily locked due to multiple failed attempts"
}

Rate Limit Exceeded (429 Too Many Requests)

{
  "error": "rate_limit_exceeded",
  "error_description": "Too many token requests. Please wait before retrying.",
  "retry_after": 300
}

Missing Required Fields (400 Bad Request)

{
  "error": "invalid_request",
  "error_description": "Missing required parameter: username"
}

Unsupported Grant Type (400 Bad Request)

{
  "error": "unsupported_grant_type",
  "error_description": "Grant type not supported"
}

Rate Limiting

The token endpoint implements rate limiting to prevent abuse:
  • Limit: 1000 requests per minute per IP address - can be customized
  • Lockout: 5 minutes after limit exceeded
  • Headers: Rate limit information included in response headers
    X-RateLimit-Limit: 10X-RateLimit-Remaining: 7X-RateLimit-Reset: 1640995200
    
    

Permission Levels

User Level

  • Access to document generation endpoints
  • Can view and generate documents for their account
  • Cannot access admin functions

Admin Level

  • All user permissions
  • Access to user management endpoints
  • Can view system metrics and logs
  • Can manage organization settings

Custom OAuth2 Provider Integration

To integrate with your own OAuth2 provider instead of PropelAuth:

Update Configuration Variables

PROPELAUTH_SIGNIN_URL=https://your-oauth-provider.com/oauth/authorize
PROPELAUTH_API_KEY=your_oauth_provider_api_key

Ensure OAuth2 Compliance

Your provider must support:
  • Standard OAuth2 grant types
  • JWT access tokens
  • User permission levels in token response
  • Rate limiting capabilities

Required Endpoints

  • /auth/token - Token issuance
  • /auth/authorize - Authorization (for web flows)
  • Token validation endpoint for API verification

Security Best Practices

  • Store credentials securely - Never log or expose passwords
  • Use HTTPS only - All authentication requests must use secure connections
  • Implement token caching - Avoid unnecessary re-authentication
  • Handle errors gracefully - Implement exponential backoff for rate limits
  • Monitor for suspicious activity - Track failed authentication attempts

Code Examples

Python Implementation

import requests
import time
from datetime import datetime, timedelta

class APIAuthenticator:
    def __init__(self, base_url, username, password):
        self.base_url = base_url
        self.username = username
        self.password = password
        self.token_data = None
        self.token_expiry = None
    
    def get_valid_token(self):
        if not self.token_data or datetime.now() >= self.token_expiry:
            self.authenticate()
        return self.token_data['access_token']
    
    def authenticate(self):
        response = requests.post(
            f"{self.base_url}/auth/token",
            json={
                "username": self.username,
                "password": self.password,
                "grant_type": "password"
            },
            headers={"Content-Type": "application/json"}
        )
        
        if response.status_code == 200:
            self.token_data = response.json()
            self.token_expiry = datetime.now() + timedelta(
                seconds=self.token_data['expires_in'] - 60  # 1 minute buffer
            )
        else:
            raise Exception(f"Authentication failed: {response.text}")
    
    def make_authenticated_request(self, method, endpoint, **kwargs):
        token = self.get_valid_token()
        headers = kwargs.get('headers', {})
        headers['Authorization'] = f"Bearer {token}"
        kwargs['headers'] = headers
        
        return requests.request(method, f"{self.base_url}{endpoint}", **kwargs)

# Usage example
auth = APIAuthenticator("https://api.yourdomain.com", "username", "password")
response = auth.make_authenticated_request("GET", "/documents")

cURL Examples

# Get token
curl -X POST "https://api.yourdomain.com/auth/token" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "your-username",
    "password": "your-password",
    "grant_type": "password"
  }'

# Use token in API call
curl -X GET "https://api.yourdomain.com/documents" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
  -H "Content-Type: application/json"

Troubleshooting

Common Issues

Problem: “Invalid username or password” error Solution: Verify credentials are correct and account exists Problem: “Account locked” error Solution: Wait for lockout period to expire, then try again Problem: “Rate limit exceeded” error Solution: Implement exponential backoff and respect retry-after header Problem: Token appears invalid Solution: Check token expiration and re-authenticate if needed

Testing Authentication

Use this endpoint to verify your token is working:
curl -X GET "https://api.yourdomain.com/auth/verify" \
  -H "Authorization: Bearer your-token-here"
Expected response:
{
  "valid": true,
  "user_level": "admin",
  "expires_at": "2024-01-01T12:00:00Z"
}