Skip to main content

Authentication

Secure your API integrations with multiple authentication methods including API keys, OAuth 2.0, and JWT tokens. Learn how to implement robust security for your applications.

Authentication Overview#

PromptReports provides multiple authentication methods to secure your API integrations. Choose the method that best fits your use case and security requirements.

API Keys

Simple, long-lived tokens for server-to-server communication. Best for backend integrations.

OAuth 2.0

Industry-standard protocol for delegated authorization. Ideal for third-party applications.

JWT Tokens

Short-lived, self-contained tokens with embedded claims. Perfect for stateless authentication.

Scoped Permissions

Fine-grained access control with customizable permission scopes for each token.

API Keys#

API keys are the simplest authentication method. They are long-lived tokens that authenticate your application to the PromptReports API. Include your API key in the Authorization header of every request.

Using API Key Authentication
bash
curl -X GET "https://api.promptreports.ai/v1/prompts" \
  -H "Authorization: Bearer pr_live_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json"
1

Generate an API Key

Navigate to your account settings and click on "API Keys" in the sidebar. Click "Create New Key" to generate a new API key.
2

Name and Configure Your Key

Give your key a descriptive name (e.g., "Production Server" or "Development") and select the appropriate scopes for the operations you need to perform.
3

Copy and Store Securely

Copy your API key immediately after creation. For security reasons, the full key is only shown once. Store it securely in your environment variables or secrets manager.
4

Use in Your Application

Include the API key in the Authorization header as a Bearer token for all API requests.
Key PrefixEnvironmentDescription
pr_live_ProductionUse for production applications with real data
pr_test_SandboxUse for testing and development with sandbox data

OAuth 2.0#

OAuth 2.0 is the recommended authentication method for third-party applications that need to access PromptReports on behalf of users. It provides secure, delegated authorization without exposing user credentials.

Supported OAuth Flows#

FlowUse CaseSecurity Level
Authorization CodeWeb applications with server-side backendHighest
Authorization Code + PKCEMobile apps, SPAs, and public clientsHighest
Client CredentialsServer-to-server communicationHigh

Authorization Code Flow#

Step 1: Redirect to Authorization
text
GET https://promptreports.ai/oauth/authorize
  ?client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.com/callback
  &response_type=code
  &scope=prompts:read prompts:write reports:read
  &state=random_state_string
Step 2: Exchange Code for Tokens
bash
curl -X POST "https://api.promptreports.ai/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://yourapp.com/callback"
Token Response
json
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "rt_xxxxxxxxxxxxxxxxxxxx",
  "scope": "prompts:read prompts:write reports:read"
}

JWT Tokens#

JWT (JSON Web Tokens) are self-contained tokens that encode user claims and permissions. They are returned when authenticating via OAuth 2.0 and can be used for stateless authentication.

JWT Token Structure
json
// Header
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "key-id-123"
}

// Payload
{
  "sub": "user_abc123",
  "iss": "https://api.promptreports.ai",
  "aud": "your-client-id",
  "exp": 1673460389,
  "iat": 1673456789,
  "scope": "prompts:read prompts:write",
  "org_id": "org_xyz789"
}

To verify JWT tokens in your application, use the PromptReports public keys available at our JWKS endpoint:

JWKS Endpoint
text
GET https://api.promptreports.ai/.well-known/jwks.json
Verifying JWT in Node.js
typescript
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';

const client = jwksClient({
  jwksUri: 'https://api.promptreports.ai/.well-known/jwks.json',
  cache: true,
  rateLimit: true,
});

async function verifyToken(token: string) {
  const decoded = jwt.decode(token, { complete: true });
  const key = await client.getSigningKey(decoded.header.kid);

  return jwt.verify(token, key.getPublicKey(), {
    algorithms: ['RS256'],
    issuer: 'https://api.promptreports.ai',
    audience: process.env.CLIENT_ID,
  });
}

Rate Limiting#

All API requests are subject to rate limiting to ensure fair usage and platform stability. Rate limits vary by authentication method and subscription plan.

PlanRequests/MinuteRequests/DayBurst Limit
Free601,00010
Pro30010,00050
Business60050,000100
Enterprise1,000+100,000+Custom

Rate limit information is included in response headers:

Rate Limit Headers
text
X-RateLimit-Limit: 300          # Maximum requests per window
X-RateLimit-Remaining: 245      # Remaining requests in current window
X-RateLimit-Reset: 1673456789   # Unix timestamp when limit resets
X-RateLimit-Policy: 300/minute  # Current rate limit policy
Retry-After: 45                 # Seconds to wait (only on 429 responses)
Handling Rate Limits
typescript
async function apiRequest(url: string, options: RequestInit) {
  const response = await fetch(url, options);

  if (response.status === 429) {
    const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
    console.log(`Rate limited. Retrying in ${retryAfter} seconds...`);

    await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
    return apiRequest(url, options); // Retry the request
  }

  // Check remaining quota
  const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
  if (remaining < 10) {
    console.warn(`Low API quota: ${remaining} requests remaining`);
  }

  return response;
}

Security Best Practices#

Follow these security best practices to protect your API integrations and user data.

Use HTTPS Only

All API requests must use HTTPS. HTTP requests are automatically rejected.

Rotate Keys Regularly

Rotate API keys and refresh tokens periodically, especially for production environments.

Server-Side Only

Keep API keys and secrets on the server. Never expose them in client-side code.

Minimum Permissions

Request only the scopes your application needs. Follow the principle of least privilege.

Secure Storage#

Environment Variables (.env)
text
# Never commit this file to version control
PROMPTREPORTS_API_KEY=pr_live_xxxxxxxxxxxxxxxxxxxx
PROMPTREPORTS_CLIENT_ID=client_abc123
PROMPTREPORTS_CLIENT_SECRET=secret_xxxxxxxx
PROMPTREPORTS_WEBHOOK_SECRET=whsec_xxxxxxxx
Using Environment Variables
typescript
// Good: Load from environment
const apiKey = process.env.PROMPTREPORTS_API_KEY;

// Bad: Hardcoded credentials
const apiKey = 'pr_live_xxxxxxxxxxxxxxxxxxxx'; // Never do this!

// Verify key is available
if (!apiKey) {
  throw new Error('PROMPTREPORTS_API_KEY environment variable is required');
}
  • Use a secrets manager (AWS Secrets Manager, HashiCorp Vault) for production deployments
  • Enable IP allowlisting if your application has fixed IP addresses
  • Monitor API key usage and set up alerts for unusual activity
  • Implement request signing for webhook endpoints
  • Use short-lived tokens where possible

Token Refresh#

Access tokens obtained via OAuth 2.0 are short-lived for security. Use the refresh token to obtain new access tokens without requiring user re-authentication.

Refreshing Access Tokens
bash
curl -X POST "https://api.promptreports.ai/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "refresh_token=rt_xxxxxxxxxxxxxxxxxxxx"
Automatic Token Refresh
typescript
class TokenManager {
  private accessToken: string;
  private refreshToken: string;
  private expiresAt: number;

  async getValidToken(): Promise<string> {
    // Refresh token 5 minutes before expiration
    if (Date.now() >= this.expiresAt - 300000) {
      await this.refreshAccessToken();
    }
    return this.accessToken;
  }

  private async refreshAccessToken(): Promise<void> {
    const response = await fetch('https://api.promptreports.ai/oauth/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        grant_type: 'refresh_token',
        client_id: process.env.CLIENT_ID!,
        client_secret: process.env.CLIENT_SECRET!,
        refresh_token: this.refreshToken,
      }),
    });

    const data = await response.json();
    this.accessToken = data.access_token;
    this.refreshToken = data.refresh_token || this.refreshToken;
    this.expiresAt = Date.now() + data.expires_in * 1000;
  }
}

Scopes & Permissions#

Scopes define what operations a token can perform. Request only the scopes your application needs for its functionality.

ScopeDescriptionAccess Level
prompts:readView prompts and their versionsRead
prompts:writeCreate, update, and delete promptsWrite
reports:readView generated reportsRead
reports:writeGenerate and manage reportsWrite
evaluations:readView evaluation resultsRead
evaluations:writeRun evaluations and manage datasetsWrite
webhooks:readView webhook configurationsRead
webhooks:writeCreate and manage webhooksWrite
organization:readView organization settingsRead
organization:adminManage organization and membersAdmin