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.
curl -X GET "https://api.promptreports.ai/v1/prompts" \
-H "Authorization: Bearer pr_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json"Generate an API Key
Name and Configure Your Key
Copy and Store Securely
Use in Your Application
API Key Security
| Key Prefix | Environment | Description |
|---|---|---|
| pr_live_ | Production | Use for production applications with real data |
| pr_test_ | Sandbox | Use 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#
| Flow | Use Case | Security Level |
|---|---|---|
| Authorization Code | Web applications with server-side backend | Highest |
| Authorization Code + PKCE | Mobile apps, SPAs, and public clients | Highest |
| Client Credentials | Server-to-server communication | High |
Authorization Code Flow#
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_stringcurl -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"{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rt_xxxxxxxxxxxxxxxxxxxx",
"scope": "prompts:read prompts:write reports:read"
}PKCE for Public Clients
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.
// 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:
GET https://api.promptreports.ai/.well-known/jwks.jsonimport 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.
| Plan | Requests/Minute | Requests/Day | Burst Limit |
|---|---|---|---|
| Free | 60 | 1,000 | 10 |
| Pro | 300 | 10,000 | 50 |
| Business | 600 | 50,000 | 100 |
| Enterprise | 1,000+ | 100,000+ | Custom |
Rate limit information is included in response headers:
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)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;
}Rate Limit Strategies
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#
# 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// 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.
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"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.
| Scope | Description | Access Level |
|---|---|---|
| prompts:read | View prompts and their versions | Read |
| prompts:write | Create, update, and delete prompts | Write |
| reports:read | View generated reports | Read |
| reports:write | Generate and manage reports | Write |
| evaluations:read | View evaluation results | Read |
| evaluations:write | Run evaluations and manage datasets | Write |
| webhooks:read | View webhook configurations | Read |
| webhooks:write | Create and manage webhooks | Write |
| organization:read | View organization settings | Read |
| organization:admin | Manage organization and members | Admin |
Scope Best Practices
organization:admin should only be requested when absolutely necessary.