API keys overview
Manage your APIs
This guide covers common API key errors in Kinde, their causes, and how to resolve them.
Here’s a summary of the most common error types.
Authentication errors
Authorization errors
Configuration errors
See below for full explanations and debugging assistance.
Symptoms:
Common causes:
Solutions:
k_live_1234567890abcdef....curl -X GET https://your-domain.kinde.com/api/users \ -H "Authorization: Bearer YOUR_API_KEY"Bearer prefix is required. Debugging steps:
Symptoms:
Common causes:
Solutions:
Implement token refresh logic
async function getValidToken(clientId, clientSecret) { try { const response = await fetch("https://your-domain.kinde.com/oauth2/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: `client_id=${encodeURIComponent(clientId)}&client_secret=${encodeURIComponent(clientSecret)}&grant_type=client_credentials` });
const data = await response.json(); return data.access_token; } catch (error) { throw new Error("Failed to obtain access token"); }}Use in your application
let accessToken = await getValidToken(clientId, clientSecret);let tokenExpiry = Date.now() + 3600000; // 1 hour
// Check if token needs refreshif (Date.now() >= tokenExpiry) { accessToken = await getValidToken(clientId, clientSecret); tokenExpiry = Date.now() + 3600000;}Debugging steps:
Symptoms:
Common causes:
Solutions:
Ensure proper header format
const headers = { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json"};For token exchange
const formData = new URLSearchParams();formData.append("client_id", clientId);formData.append("client_secret", clientSecret);formData.append("grant_type", "client_credentials");
const response = await fetch("https://your-domain.kinde.com/oauth2/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: formData});Symptoms:
Common causes:
Solutions:
Debugging steps:
Symptoms:
Common causes:
Solutions:
Verify organization in token:
function validateOrganizationAccess(token, requiredOrgCode) { if (!token.org_code) { throw new Error("Organization-scoped token required"); }
if (token.org_code !== requiredOrgCode) { throw new Error("Access denied: organization mismatch"); }
return true;}Use in your API endpoint
app.get("/api/users/:userId", async (req, res) => { try { const token = extractTokenFromRequest(req); const user = await getUserById(req.params.userId);
// Validate organization access validateOrganizationAccess(token, user.organization_code);
res.json(user); } catch (error) { res.status(403).json({error: error.message}); }});Debugging steps:
Symptoms:
Common causes:
Solutions:
Implement rate limiting in your application
class RateLimiter { constructor(limit, window) { this.limit = limit; this.window = window; this.requests = new Map(); }
checkLimit(key) { const now = Date.now(); const windowStart = now - this.window;
// Clean old entries if (this.requests.has(key)) { this.requests.set( key, this.requests.get(key).filter((timestamp) => timestamp > windowStart) ); }
const currentRequests = this.requests.get(key) || [];
if (currentRequests.length >= this.limit) { return false; // Rate limited }
currentRequests.push(now); this.requests.set(key, currentRequests); return true; }}Usage
const rateLimiter = new RateLimiter(100, 60000); // 100 requests per minute
if (!rateLimiter.checkLimit(apiKey)) { throw new Error("Rate limit exceeded. Please try again later.");}Debugging steps:
Symptoms:
Common causes:
Solutions:
Check available scopes:
Common standard scopes:
Debugging steps:
It’s always better to prevent errors than deal with them under pressure. Here are some tips for long-term API key management.