The API Keys app enables your users to generate and manage API keys for programmatic access to your backend services. API keys provide a secure way to authenticate requests, allowing developers to associate API calls with specific users or teams. Stack Auth provides prebuilt UI components for users and teams to manage their own API keys.Documentation Index
Fetch the complete documentation index at: https://stackauth-e0affa27-apps-support.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Overview
API keys allow your users to access your backend services programmatically without interactive authentication. The flow works as follows: a user or client sends an API request with an API key to your application server. Your server validates the API key with Stack Auth, which returns an authenticated User object. Your server then processes the request and returns the response. Stack Auth provides two types of API keys:User API keys
User API keys are associated with individual users and allow them to authenticate with your API.- Next.js Client
- Next.js Server
- React
- Django
- FastAPI
- Flask
app/components/create-api-key.tsx
"use client";
import { useUser } from "@stackframe/stack";
export default function CreateApiKey() {
const user = useUser({ or: 'redirect' });
const handleCreateKey = async () => {
const apiKey = await user.createApiKey({
description: "My client application",
expiresAt: new Date(Date.now() + (90 * 24 * 60 * 60 * 1000)), // 90 days
});
console.log("API Key created:", apiKey.value);
};
return <button onClick={handleCreateKey}>Create API Key</button>;
}
app/components/create-api-key.tsx
import { stackServerApp } from "@/stack/server";
export default async function CreateApiKey() {
const user = await stackServerApp.getUser({ or: 'redirect' });
const apiKey = await user.createApiKey({
description: "Admin-provisioned API key",
expiresAt: new Date(Date.now() + (30 * 24 * 60 * 60 * 1000)), // 30 days
});
return <div>API Key: {apiKey.value}</div>;
}
components/CreateApiKey.tsx
"use client";
import { useUser } from "@stackframe/react";
export default function CreateApiKey() {
const user = useUser({ or: 'redirect' });
const handleCreateKey = async () => {
const apiKey = await user.createApiKey({
description: "My client application",
expiresAt: new Date(Date.now() + (90 * 24 * 60 * 60 * 1000)), // 90 days
});
console.log("API Key created:", apiKey.value);
};
return <button onClick={handleCreateKey}>Create API Key</button>;
}
views.py
import requests
from django.http import JsonResponse
def create_user_api_key(request):
# Get the current user's access token from session/cookie
access_token = request.COOKIES.get('stack-access-token')
# Create API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/user-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
},
json={
'user_id': 'me',
'description': 'My client application',
'expires_at_millis': int((time.time() + 90 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
raise Exception(f"Failed to create API key: {response.text}")
return JsonResponse(response.json())
main.py
import requests
import time
from fastapi import Cookie, HTTPException
@app.post("/api/create-user-api-key")
async def create_user_api_key(stack_access_token: str = Cookie(None, alias="stack-access-token")):
if not stack_access_token:
raise HTTPException(status_code=401, detail="Not authenticated")
# Create API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/user-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': stack_access_token,
},
json={
'user_id': 'me',
'description': 'My client application',
'expires_at_millis': int((time.time() + 90 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
raise HTTPException(status_code=response.status_code, detail=response.text)
return response.json()
app.py
import requests
import time
from flask import request, jsonify
@app.route('/api/create-user-api-key', methods=['POST'])
def create_user_api_key():
access_token = request.cookies.get('stack-access-token')
if not access_token:
return jsonify({'error': 'Not authenticated'}), 401
# Create API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/user-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
},
json={
'user_id': 'me',
'description': 'My client application',
'expires_at_millis': int((time.time() + 90 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
return jsonify({'error': response.text}), response.status_code
return jsonify(response.json())
Team API keys
Team API keys are associated with teams and can be used to provide access to team resources over your API.- Next.js Client
- Next.js Server
- React
- Django
- FastAPI
- Flask
app/components/create-team-api-key.tsx
"use client";
import { useUser } from "@stackframe/stack";
export default function CreateTeamApiKey({ teamId }: { teamId: string }) {
const user = useUser({ or: 'redirect' });
const team = user.useTeam(teamId);
const handleCreateKey = async () => {
if (!team) return;
const teamApiKey = await team.createApiKey({
description: "Team integration service",
expiresAt: new Date(Date.now() + (60 * 24 * 60 * 60 * 1000)), // 60 days
});
console.log("Team API Key created:", teamApiKey.value);
};
return <button onClick={handleCreateKey}>Create Team API Key</button>;
}
app/components/create-team-api-key.tsx
import { stackServerApp } from "@/stack/server";
export default async function CreateTeamApiKey({ teamId }: { teamId: string }) {
const team = await stackServerApp.getTeam(teamId);
if (!team) {
return <div>Team not found</div>;
}
const teamApiKey = await team.createApiKey({
description: "Admin-provisioned team API key",
expiresAt: new Date(Date.now() + (30 * 24 * 60 * 60 * 1000)), // 30 days
});
return <div>Team API Key: {teamApiKey.value}</div>;
}
components/CreateTeamApiKey.tsx
"use client";
import { useUser } from "@stackframe/react";
export default function CreateTeamApiKey({ teamId }: { teamId: string }) {
const user = useUser({ or: 'redirect' });
const team = user.useTeam(teamId);
const handleCreateKey = async () => {
if (!team) return;
const teamApiKey = await team.createApiKey({
description: "Team integration service",
expiresAt: new Date(Date.now() + (60 * 24 * 60 * 60 * 1000)), // 60 days
});
console.log("Team API Key created:", teamApiKey.value);
};
return <button onClick={handleCreateKey}>Create Team API Key</button>;
}
views.py
import requests
import time
from django.http import JsonResponse
def create_team_api_key(request, team_id):
# Get the current user's access token from session/cookie
access_token = request.COOKIES.get('stack-access-token')
# Create team API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/team-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
},
json={
'team_id': team_id,
'description': 'Team integration service',
'expires_at_millis': int((time.time() + 60 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
raise Exception(f"Failed to create team API key: {response.text}")
return JsonResponse(response.json())
main.py
import requests
import time
from fastapi import Cookie, HTTPException
@app.post("/api/teams/{team_id}/api-keys")
async def create_team_api_key(team_id: str, stack_access_token: str = Cookie(None, alias="stack-access-token")):
if not stack_access_token:
raise HTTPException(status_code=401, detail="Not authenticated")
# Create team API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/team-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': stack_access_token,
},
json={
'team_id': team_id,
'description': 'Team integration service',
'expires_at_millis': int((time.time() + 60 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
raise HTTPException(status_code=response.status_code, detail=response.text)
return response.json()
app.py
import requests
import time
from flask import request, jsonify
@app.route('/api/teams/<team_id>/api-keys', methods=['POST'])
def create_team_api_key(team_id):
access_token = request.cookies.get('stack-access-token')
if not access_token:
return jsonify({'error': 'Not authenticated'}), 401
# Create team API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/team-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
},
json={
'team_id': team_id,
'description': 'Team integration service',
'expires_at_millis': int((time.time() + 60 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
return jsonify({'error': response.text}), response.status_code
return jsonify(response.json())
Enabling the API Keys App
To use API keys in your application, you need to enable the API Keys app in your Stack Auth dashboard:- Navigate to your Stack Auth dashboard
- Go to the Apps section
- Find and click on API Keys in the app store
- Click the Enable button
Prebuilt UI Components
Stack Auth provides prebuilt UI components that allow your users to manage their own API keys without any additional code:User API Keys UI
For frameworks that support React components, the<AccountSettings> component includes an API Keys tab where users can:
- View all their active API keys
- Create new API keys with custom descriptions and expiration dates
- Revoke existing API keys
- See when each key was created and when it expires.
- Next.js
- React
app/src/account-page.tsx
import { AccountSettings } from '@stackframe/stack';
export default function MyAccountPage() {
return (
<AccountSettings
fullPage={true}
/>
);
}
app/src/account-page.tsx
import { AccountSettings } from '@stackframe/react';
export default function MyAccountPage() {
return (
<AccountSettings
fullPage={true}
/>
);
}
Team API Keys UI
For team API keys, the team settings page automatically includes an API Keys section when:- The API Keys app is enabled
allowTeamApiKeysis configured in your project settings- The user has the
$manage_api_keyspermission for the team
Working with API Keys
Creating User API Keys
- Next.js Client
- Next.js Server
- React
- Django
- FastAPI
- Flask
app/components/create-api-key.tsx
"use client";
import { useUser } from "@stackframe/stack";
export default function CreateApiKey() {
const user = useUser({ or: 'redirect' });
const handleCreateKey = async () => {
const apiKey = await user.createApiKey({
description: "My client application",
expiresAt: new Date(Date.now() + (90 * 24 * 60 * 60 * 1000)), // 90 days
});
console.log("API Key created:", apiKey.value);
};
return <button onClick={handleCreateKey}>Create API Key</button>;
}
app/components/create-api-key.tsx
import { stackServerApp } from "@/stack/server";
export default async function CreateApiKey() {
const user = await stackServerApp.getUser({ or: 'redirect' });
const apiKey = await user.createApiKey({
description: "Admin-provisioned API key",
expiresAt: new Date(Date.now() + (30 * 24 * 60 * 60 * 1000)), // 30 days
});
return <div>API Key: {apiKey.value}</div>;
}
components/CreateApiKey.tsx
"use client";
import { useUser } from "@stackframe/react";
export default function CreateApiKey() {
const user = useUser({ or: 'redirect' });
const handleCreateKey = async () => {
const apiKey = await user.createApiKey({
description: "My client application",
expiresAt: new Date(Date.now() + (90 * 24 * 60 * 60 * 1000)), // 90 days
});
console.log("API Key created:", apiKey.value);
};
return <button onClick={handleCreateKey}>Create API Key</button>;
}
views.py
import requests
from django.http import JsonResponse
def create_user_api_key(request):
# Get the current user's access token from session/cookie
access_token = request.COOKIES.get('stack-access-token')
# Create API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/user-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
},
json={
'user_id': 'me',
'description': 'My client application',
'expires_at_millis': int((time.time() + 90 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
raise Exception(f"Failed to create API key: {response.text}")
return JsonResponse(response.json())
main.py
import requests
import time
from fastapi import Cookie, HTTPException
@app.post("/api/create-user-api-key")
async def create_user_api_key(stack_access_token: str = Cookie(None, alias="stack-access-token")):
if not stack_access_token:
raise HTTPException(status_code=401, detail="Not authenticated")
# Create API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/user-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': stack_access_token,
},
json={
'user_id': 'me',
'description': 'My client application',
'expires_at_millis': int((time.time() + 90 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
raise HTTPException(status_code=response.status_code, detail=response.text)
return response.json()
app.py
import requests
import time
from flask import request, jsonify
@app.route('/api/create-user-api-key', methods=['POST'])
def create_user_api_key():
access_token = request.cookies.get('stack-access-token')
if not access_token:
return jsonify({'error': 'Not authenticated'}), 401
# Create API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/user-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
},
json={
'user_id': 'me',
'description': 'My client application',
'expires_at_millis': int((time.time() + 90 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
return jsonify({'error': response.text}), response.status_code
return jsonify(response.json())
Creating Team API Keys
- Next.js Client
- Next.js Server
- React
- Django
- FastAPI
- Flask
app/components/create-team-api-key.tsx
"use client";
import { useUser } from "@stackframe/stack";
export default function CreateTeamApiKey({ teamId }: { teamId: string }) {
const user = useUser({ or: 'redirect' });
const team = user.useTeam(teamId);
const handleCreateKey = async () => {
if (!team) return;
const teamApiKey = await team.createApiKey({
description: "Team integration service",
expiresAt: new Date(Date.now() + (60 * 24 * 60 * 60 * 1000)), // 60 days
});
console.log("Team API Key created:", teamApiKey.value);
};
return <button onClick={handleCreateKey}>Create Team API Key</button>;
}
app/components/create-team-api-key.tsx
import { stackServerApp } from "@/stack/server";
export default async function CreateTeamApiKey({ teamId }: { teamId: string }) {
const team = await stackServerApp.getTeam(teamId);
if (!team) {
return <div>Team not found</div>;
}
const teamApiKey = await team.createApiKey({
description: "Admin-provisioned team API key",
expiresAt: new Date(Date.now() + (30 * 24 * 60 * 60 * 1000)), // 30 days
});
return <div>Team API Key: {teamApiKey.value}</div>;
}
components/CreateTeamApiKey.tsx
"use client";
import { useUser } from "@stackframe/react";
export default function CreateTeamApiKey({ teamId }: { teamId: string }) {
const user = useUser({ or: 'redirect' });
const team = user.useTeam(teamId);
const handleCreateKey = async () => {
if (!team) return;
const teamApiKey = await team.createApiKey({
description: "Team integration service",
expiresAt: new Date(Date.now() + (60 * 24 * 60 * 60 * 1000)), // 60 days
});
console.log("Team API Key created:", teamApiKey.value);
};
return <button onClick={handleCreateKey}>Create Team API Key</button>;
}
views.py
import requests
import time
from django.http import JsonResponse
def create_team_api_key(request, team_id):
# Get the current user's access token from session/cookie
access_token = request.COOKIES.get('stack-access-token')
# Create team API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/team-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
},
json={
'team_id': team_id,
'description': 'Team integration service',
'expires_at_millis': int((time.time() + 60 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
raise Exception(f"Failed to create team API key: {response.text}")
return JsonResponse(response.json())
main.py
import requests
import time
from fastapi import Cookie, HTTPException
@app.post("/api/teams/{team_id}/api-keys")
async def create_team_api_key(team_id: str, stack_access_token: str = Cookie(None, alias="stack-access-token")):
if not stack_access_token:
raise HTTPException(status_code=401, detail="Not authenticated")
# Create team API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/team-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': stack_access_token,
},
json={
'team_id': team_id,
'description': 'Team integration service',
'expires_at_millis': int((time.time() + 60 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
raise HTTPException(status_code=response.status_code, detail=response.text)
return response.json()
app.py
import requests
import time
from flask import request, jsonify
@app.route('/api/teams/<team_id>/api-keys', methods=['POST'])
def create_team_api_key(team_id):
access_token = request.cookies.get('stack-access-token')
if not access_token:
return jsonify({'error': 'Not authenticated'}), 401
# Create team API key via client API
response = requests.post(
'https://api.stack-auth.com/api/v1/team-api-keys',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
},
json={
'team_id': team_id,
'description': 'Team integration service',
'expires_at_millis': int((time.time() + 60 * 24 * 60 * 60) * 1000),
}
)
if response.status_code != 200:
return jsonify({'error': response.text}), response.status_code
return jsonify(response.json())
Listing API Keys
- Next.js Client
- Next.js Server
- React
- Django
- FastAPI
- Flask
app/components/api-keys-list.tsx
"use client";
import { useUser } from "@stackframe/stack";
export default function ApiKeysList() {
const user = useUser({ or: 'redirect' });
const apiKeys = user.useApiKeys();
return (
<div>
<h2>Your API Keys</h2>
{apiKeys.map(key => (
<div key={key.id}>
<p>{key.description}</p>
<p>Last 4 digits: {key.value.lastFour}</p>
<p>Created: {key.createdAt.toLocaleDateString()}</p>
</div>
))}
</div>
);
}
app/components/api-keys-list.tsx
import { stackServerApp } from "@/stack/server";
export default async function ApiKeysList() {
const user = await stackServerApp.getUser({ or: 'redirect' });
const apiKeys = await user.listApiKeys();
return (
<div>
<h2>Your API Keys</h2>
{apiKeys.map(key => (
<div key={key.id}>
<p>{key.description}</p>
<p>Last 4 digits: {key.value.lastFour}</p>
<p>Created: {key.createdAt.toLocaleDateString()}</p>
</div>
))}
</div>
);
}
components/ApiKeysList.tsx
"use client";
import { useUser } from "@stackframe/react";
export default function ApiKeysList() {
const user = useUser({ or: 'redirect' });
const apiKeys = user.useApiKeys();
return (
<div>
<h2>Your API Keys</h2>
{apiKeys.map(key => (
<div key={key.id}>
<p>{key.description}</p>
<p>Last 4 digits: {key.value.lastFour}</p>
<p>Created: {key.createdAt.toLocaleDateString()}</p>
</div>
))}
</div>
);
}
views.py
import requests
from django.http import JsonResponse
def list_user_api_keys(request):
# Get the current user's access token from session/cookie
access_token = request.COOKIES.get('stack-access-token')
# List user's API keys via client API
response = requests.get(
'https://api.stack-auth.com/api/v1/user-api-keys?user_id=me',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
}
)
if response.status_code != 200:
raise Exception(f"Failed to list API keys: {response.text}")
return JsonResponse(response.json(), safe=False)
main.py
import requests
from fastapi import Cookie, HTTPException
@app.get("/api/user-api-keys")
async def list_user_api_keys(stack_access_token: str = Cookie(None, alias="stack-access-token")):
if not stack_access_token:
raise HTTPException(status_code=401, detail="Not authenticated")
# List user's API keys via client API
response = requests.get(
'https://api.stack-auth.com/api/v1/user-api-keys?user_id=me',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': stack_access_token,
}
)
if response.status_code != 200:
raise HTTPException(status_code=response.status_code, detail=response.text)
return response.json()
app.py
import requests
from flask import request, jsonify
@app.route('/api/user-api-keys', methods=['GET'])
def list_user_api_keys():
access_token = request.cookies.get('stack-access-token')
if not access_token:
return jsonify({'error': 'Not authenticated'}), 401
# List user's API keys via client API
response = requests.get(
'https://api.stack-auth.com/api/v1/user-api-keys?user_id=me',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
}
)
if response.status_code != 200:
return jsonify({'error': response.text}), response.status_code
return jsonify(response.json())
Revoking API Keys
API keys can be revoked when they are no longer needed or if they have been compromised.- Next.js Client
- Next.js Server
- React
- Django
- FastAPI
- Flask
app/components/revoke-api-key.tsx
"use client";
import { useUser } from "@stackframe/stack";
export default function RevokeApiKey({ apiKeyId }: { apiKeyId: string }) {
const user = useUser({ or: 'redirect' });
const apiKeys = user.useApiKeys();
const handleRevoke = async () => {
const apiKeyToRevoke = apiKeys.find(key => key.id === apiKeyId);
if (apiKeyToRevoke) {
await apiKeyToRevoke.revoke();
console.log("API Key revoked");
}
};
return <button onClick={handleRevoke}>Revoke API Key</button>;
}
lib/api-keys.ts
import { stackServerApp } from "@/stack/server";
export async function revokeApiKey(userId: string, apiKeyId: string) {
const user = await stackServerApp.getUser(userId);
if (!user) return;
const apiKeys = await user.listApiKeys();
const apiKeyToRevoke = apiKeys.find(key => key.id === apiKeyId);
if (apiKeyToRevoke) {
await apiKeyToRevoke.revoke();
}
}
components/RevokeApiKey.tsx
"use client";
import { useUser } from "@stackframe/react";
export default function RevokeApiKey({ apiKeyId }: { apiKeyId: string }) {
const user = useUser({ or: 'redirect' });
const apiKeys = user.useApiKeys();
const handleRevoke = async () => {
const apiKeyToRevoke = apiKeys.find(key => key.id === apiKeyId);
if (apiKeyToRevoke) {
await apiKeyToRevoke.revoke();
console.log("API Key revoked");
}
};
return <button onClick={handleRevoke}>Revoke API Key</button>;
}
views.py
import requests
from django.http import JsonResponse
def revoke_api_key(request, api_key_id):
# Get the current user's access token from session/cookie
access_token = request.COOKIES.get('stack-access-token')
# Revoke API key via client API (update with revoked: true)
response = requests.patch(
f'https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
},
json={
'revoked': True,
}
)
if response.status_code != 200:
raise Exception(f"Failed to revoke API key: {response.text}")
return JsonResponse({'message': 'API key revoked successfully'})
main.py
import requests
from fastapi import Cookie, HTTPException
@app.delete("/api/user-api-keys/{api_key_id}")
async def revoke_api_key(api_key_id: str, stack_access_token: str = Cookie(None, alias="stack-access-token")):
if not stack_access_token:
raise HTTPException(status_code=401, detail="Not authenticated")
# Revoke API key via client API (update with revoked: true)
response = requests.patch(
f'https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': stack_access_token,
},
json={
'revoked': True,
}
)
if response.status_code != 200:
raise HTTPException(status_code=response.status_code, detail=response.text)
return {"message": "API key revoked successfully"}
app.py
import requests
from flask import request, jsonify
@app.route('/api/user-api-keys/<api_key_id>', methods=['DELETE'])
def revoke_api_key(api_key_id):
access_token = request.cookies.get('stack-access-token')
if not access_token:
return jsonify({'error': 'Not authenticated'}), 401
# Revoke API key via client API (update with revoked: true)
response = requests.patch(
f'https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
},
json={
'revoked': True,
}
)
if response.status_code != 200:
return jsonify({'error': response.text}), response.status_code
return jsonify({'message': 'API key revoked successfully'})
Checking API Key Validity
You can check if an API key is still valid:- Next.js Client
- Next.js Server
- React
- Django
- FastAPI
- Flask
app/components/check-api-key.tsx
"use client";
import { useUser } from "@stackframe/stack";
export default function CheckApiKeyValidity({ apiKeyId }: { apiKeyId: string }) {
const user = useUser({ or: 'redirect' });
const apiKeys = user.useApiKeys();
const apiKey = apiKeys.find(key => key.id === apiKeyId);
if (!apiKey) {
return <div>API key not found</div>;
}
if (apiKey.isValid()) {
return <div>API key is valid</div>;
}
const reason = apiKey.whyInvalid();
return <div>API key is invalid: {reason}</div>;
}
app/components/check-api-key.tsx
import { stackServerApp } from "@/stack/server";
export default async function CheckApiKeyValidity({
userId,
apiKeyId
}: {
userId: string,
apiKeyId: string
}) {
const user = await stackServerApp.getUser(userId);
if (!user) return <div>User not found</div>;
const apiKeys = await user.listApiKeys();
const apiKey = apiKeys.find(key => key.id === apiKeyId);
if (!apiKey) {
return <div>API key not found</div>;
}
if (apiKey.isValid()) {
return <div>API key is valid</div>;
}
const reason = apiKey.whyInvalid();
return <div>API key is invalid: {reason}</div>;
}
components/CheckApiKey.tsx
"use client";
import { useUser } from "@stackframe/react";
export default function CheckApiKeyValidity({ apiKeyId }: { apiKeyId: string }) {
const user = useUser({ or: 'redirect' });
const apiKeys = user.useApiKeys();
const apiKey = apiKeys.find(key => key.id === apiKeyId);
if (!apiKey) {
return <div>API key not found</div>;
}
if (apiKey.isValid()) {
return <div>API key is valid</div>;
}
const reason = apiKey.whyInvalid();
return <div>API key is invalid: {reason}</div>;
}
views.py
import requests
import time
from django.http import JsonResponse
def check_api_key_validity(request, api_key_id):
# Get the current user's access token from session/cookie
access_token = request.COOKIES.get('stack-access-token')
# Get API key details via client API
response = requests.get(
f'https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
}
)
if response.status_code != 200:
return JsonResponse({'error': 'API key not found'}, status=404)
api_key = response.json()
# Check if manually revoked
if api_key.get('manually_revoked_at_millis'):
return JsonResponse({
'valid': False,
'reason': 'manually-revoked'
})
# Check if expired
if api_key.get('expires_at_millis'):
if api_key['expires_at_millis'] < time.time() * 1000:
return JsonResponse({
'valid': False,
'reason': 'expired'
})
return JsonResponse({'valid': True})
main.py
import requests
import time
from fastapi import Cookie, HTTPException
@app.get("/api/check-api-key/{api_key_id}")
async def check_api_key_validity(api_key_id: str, stack_access_token: str = Cookie(None, alias="stack-access-token")):
if not stack_access_token:
raise HTTPException(status_code=401, detail="Not authenticated")
# Get API key details via client API
response = requests.get(
f'https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': stack_access_token,
}
)
if response.status_code != 200:
raise HTTPException(status_code=404, detail="API key not found")
api_key = response.json()
# Check if manually revoked
if api_key.get('manually_revoked_at_millis'):
return {
'valid': False,
'reason': 'manually-revoked'
}
# Check if expired
if api_key.get('expires_at_millis'):
if api_key['expires_at_millis'] < time.time() * 1000:
return {
'valid': False,
'reason': 'expired'
}
return {'valid': True}
app.py
import requests
import time
from flask import request, jsonify
@app.route('/api/check-api-key/<api_key_id>', methods=['GET'])
def check_api_key_validity(api_key_id):
access_token = request.cookies.get('stack-access-token')
if not access_token:
return jsonify({'error': 'Not authenticated'}), 401
# Get API key details via client API
response = requests.get(
f'https://api.stack-auth.com/api/v1/user-api-keys/{api_key_id}',
headers={
'x-stack-access-type': 'client',
'x-stack-project-id': stack_project_id,
'x-stack-publishable-client-key': stack_publishable_client_key,
'x-stack-access-token': access_token,
}
)
if response.status_code != 200:
return jsonify({'error': 'API key not found'}), 404
api_key = response.json()
# Check if manually revoked
if api_key.get('manually_revoked_at_millis'):
return jsonify({
'valid': False,
'reason': 'manually-revoked'
})
# Check if expired
if api_key.get('expires_at_millis'):
if api_key['expires_at_millis'] < time.time() * 1000:
return jsonify({
'valid': False,
'reason': 'expired'
})
return jsonify({'valid': True})