Managing API access for third-party developers requires balancing security with developer experience, especially when permissions must be granular and revocable. Clerk provides backend API key infrastructure designed to issue, scope, and revoke credentials for third-party integrations with minimal operational overhead. Clerk's API key endpoints enable you to create narrowly-scoped credentials that third-party developers can use, following principle of least privilege. Revocation and verification endpoints ensure you can instantly disable compromised keys and audit access without service disruption.
What this tutorial covers
- •Outcome: You will be able to create scoped API keys for partners, verify their validity, update permissions, and revoke access instantly when needed.
- •Endpoints used: `POST backend.api-keys.create`, `PATCH backend.api-keys.update`, `DELETE backend.api-keys.revoke`, `GET backend.api-keys.list`, `POST backend.api-keys.verify`
- •Language: typescript
- •Auth: API key (Authorization: Bearer header)
- •Estimated implementation time: ~18 minutes
Step 1: Create a scoped API key in Clerk for a partner integration
Third-party integrations require credentials restricted to specific resources and actions. Clerk's create endpoint generates a new API key with defined scopes. By specifying scopes upfront (e.g., 'read:orders', 'write:webhooks'), you enforce least privilege and reduce blast radius if the key is compromised.
Create a new scoped API key
1import fetch from 'node-fetch';
2
3const createApiKey = async (partnerId: string, scopes: string[]) => {
4 const response = await fetch(
5 'https://api.clerk.com/backend.api-keys.create',
6 {
7 method: 'POST',
8 headers: {
9 'Authorization': `Bearer ${process.env.CLERK_SECRET_KEY}`,
10 'Content-Type': 'application/json',
11 },
12 body: JSON.stringify({
13 name: `partner-${partnerId}-integration`,
14 scopes,
15 metadata: {
16 partner_id: partnerId,
17 created_at: new Date().toISOString(),
18 },
19 }),
20 }
21 );
22 return response.json();
23};
24
25// Example usage
26const key = await createApiKey('acme-corp', [
27 'read:orders',
28 'read:customers',
29 'write:webhooks',
30]);Response:
1{
2 "id": "key_2lx0y5Z8kQ9pR3mN",
3 "name": "partner-acme-corp-integration",
4 "scopes": ["read:orders", "read:customers", "write:webhooks"],
5 "key": "sk_live_4v7x2jK9lQ8mN3pR5",
6 "created_at": "2024-01-15T10:30:00Z",
7 "metadata": {
8 "partner_id": "acme-corp",
9 "created_at": "2024-01-15T10:30:00Z"
10 }
11}Step 2: Verify an API key before granting access in Clerk
When a partner submits their API key, verify it is valid, active, and has the required scopes before allowing them access to your resources. Clerk's verify endpoint confirms the key's identity, scope membership, and revocation status in a single call.
Verify key validity and scopes
1const verifyApiKey = async (submittedKey: string) => {
2 const response = await fetch(
3 'https://api.clerk.com/backend.api-keys.verify',
4 {
5 method: 'POST',
6 headers: {
7 'Authorization': `Bearer ${process.env.CLERK_SECRET_KEY}`,
8 'Content-Type': 'application/json',
9 },
10 body: JSON.stringify({
11 key: submittedKey,
12 }),
13 }
14 );
15 return response.json();
16};
17
18// Example usage: validate before granting partner access
19const validation = await verifyApiKey(partnerProvidedKey);
20
21if (validation.valid && validation.scopes.includes('read:orders')) {
22 console.log('Partner can access orders');
23} else {
24 console.log('Key revoked or missing required scope');
25}Response:
1{
2 "id": "key_2lx0y5Z8kQ9pR3mN",
3 "valid": true,
4 "revoked": false,
5 "scopes": ["read:orders", "read:customers", "write:webhooks"],
6 "created_at": "2024-01-15T10:30:00Z",
7 "last_used_at": "2024-01-16T14:22:15Z"
8}Step 3: List all API keys and audit who has access in Clerk
Maintain visibility over all issued keys to detect unauthorized integrations or stale credentials. Clerk's list endpoint returns metadata and usage history. Filtering by partner metadata helps you track which keys belong to which third parties and when they were last accessed.
Retrieve all active keys with metadata
1const listApiKeys = async (limit: number = 50) => {
2 const response = await fetch(
3 `https://api.clerk.com/backend.api-keys.list?limit=${limit}`,
4 {
5 method: 'GET',
6 headers: {
7 'Authorization': `Bearer ${process.env.CLERK_SECRET_KEY}`,
8 },
9 }
10 );
11 return response.json();
12};
13
14// Example usage: audit active keys
15const allKeys = await listApiKeys();
16
17const revokedOrStale = allKeys.data.filter(
18 (key: any) =>
19 key.revoked ||
20 new Date(key.last_used_at).getTime() <
21 Date.now() - 90 * 24 * 60 * 60 * 1000 // 90 days
22);
23
24console.log(`Found ${revokedOrStale.length} stale or revoked keys`);Response:
1{
2 "data": [
3 {
4 "id": "key_2lx0y5Z8kQ9pR3mN",
5 "name": "partner-acme-corp-integration",
6 "scopes": ["read:orders", "read:customers", "write:webhooks"],
7 "created_at": "2024-01-15T10:30:00Z",
8 "last_used_at": "2024-01-16T14:22:15Z",
9 "revoked": false,
10 "metadata": {"partner_id": "acme-corp"}
11 }
12 ],
13 "total_count": 1,
14 "page": 1,
15 "page_size": 50
16}Step 4: Revoke an API key instantly when an integration is compromised
When a partner reports a leak or an integration is no longer trusted, Clerk's revoke endpoint instantly disables the key, preventing further access. Revocation is immediate and cannot be undone, making it the primary defense against compromised credentials in multi-tenant systems.
Instantly revoke an API key
1const revokeApiKey = async (keyId: string) => {
2 const response = await fetch(
3 `https://api.clerk.com/backend.api-keys.revoke`,
4 {
5 method: 'DELETE',
6 headers: {
7 'Authorization': `Bearer ${process.env.CLERK_SECRET_KEY}`,
8 'Content-Type': 'application/json',
9 },
10 body: JSON.stringify({
11 key_id: keyId,
12 }),
13 }
14 );
15 return response.json();
16};
17
18// Example usage: respond to a security incident
19const keyId = 'key_2lx0y5Z8kQ9pR3mN';
20const result = await revokeApiKey(keyId);
21
22if (result.success) {
23 console.log(`Key ${keyId} revoked immediately`);
24 // Partner can no longer authenticate with this key
25} else {
26 console.error('Revocation failed:', result.error);
27}Response:
1{
2 "id": "key_2lx0y5Z8kQ9pR3mN",
3 "revoked": true,
4 "revoked_at": "2024-01-17T09:15:22Z",
5 "success": true
6}Step 5: Update scopes to restrict an API key without revocation
If a partner's integration scope needs to be reduced (e.g., removing 'write:webhooks'), Clerk's update endpoint modifies permissions without issuing a new key. This approach lets you maintain continuity while tightening access controls in response to usage patterns or security reviews.
Update key scopes and metadata
1const updateApiKey = async (
2 keyId: string,
3 updates: { scopes?: string[]; metadata?: Record<string, any> }
4) => {
5 const response = await fetch(
6 `https://api.clerk.com/backend.api-keys.update`,
7 {
8 method: 'PATCH',
9 headers: {
10 'Authorization': `Bearer ${process.env.CLERK_SECRET_KEY}`,
11 'Content-Type': 'application/json',
12 },
13 body: JSON.stringify({
14 key_id: keyId,
15 ...updates,
16 }),
17 }
18 );
19 return response.json();
20};
21
22// Example usage: reduce scopes after security review
23const result = await updateApiKey('key_2lx0y5Z8kQ9pR3mN', {
24 scopes: ['read:orders', 'read:customers'], // removed 'write:webhooks'
25 metadata: {
26 partner_id: 'acme-corp',
27 scope_reduced_at: new Date().toISOString(),
28 reason: 'security-review',
29 },
30});
31
32console.log('Updated scopes:', result.scopes);Response:
1{
2 "id": "key_2lx0y5Z8kQ9pR3mN",
3 "name": "partner-acme-corp-integration",
4 "scopes": ["read:orders", "read:customers"],
5 "metadata": {
6 "partner_id": "acme-corp",
7 "scope_reduced_at": "2024-01-17T10:45:30Z",
8 "reason": "security-review"
9 },
10 "updated_at": "2024-01-17T10:45:30Z"
11}Common pitfalls when using Clerk
- •Issuing broad, unlimited scopes. Keys granted all scopes or wildcard permissions ('*') violate least privilege and create a large blast radius if compromised. Always scope to the minimum actions required: 'read:orders' instead of 'admin:all'. OWASP API Security Top 10 (2023) explicitly flags overly broad permissions as a critical authorization risk.
- •Storing unencrypted keys in partner code or logs. Once issued, API keys are bearer credentials—treat them like passwords. Advise partners to store keys in environment variables or secure vaults, never in version control or logs. The OAuth 2.0 Security Best Current Practice warns that long-lived bearer tokens significantly increase risk when exfiltrated.
- •Forgetting to audit and rotate old keys. Keys without rotation or access logs become stale security liabilities. Use Clerk's list endpoint regularly to identify keys unused for 60+ days and revoke them. NIST SP 800-63B recommends timely revocation and re-issuance to limit the window of compromise for API-based access.
- •Revocation delays or lack of instant enforcement. If revocation is delayed or cached, a compromised key may remain valid for minutes or hours. Clerk revokes immediately; ensure your integration tier does not cache key validity checks. HashiCorp Vault and GitHub emphasize that instant revocation reduces the blast radius in multi-tenant systems.
Ready to secure your third-party integrations with scoped, revocable API keys? Get started with Clerk.
Documentation references
The code examples in this tutorial are grounded in the following docs pages:
- •
- •
- •
- •
- •
Want seamless auth for your next app?
Join leading teams using Clerk’s authentication platform to accelerate launches, scale securely, and delight users from day one.

