---
title: "API Keys"
description: "Create and manage API keys for users and teams"
icon: "key"
---

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.

## 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.

<Tabs>
  <Tab title="Next.js Client">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Next.js Server">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="React">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Django">
    ```python title="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())
    ```
  </Tab>
  <Tab title="FastAPI">
    ```python title="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()
    ```
  </Tab>
  <Tab title="Flask">
    ```python title="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())
    ```
  </Tab>
</Tabs>

### Team API keys

Team API keys are associated with teams and can be used to provide access to team resources over your API.

<Tabs>
  <Tab title="Next.js Client">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Next.js Server">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="React">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Django">
    ```python title="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())
    ```
  </Tab>
  <Tab title="FastAPI">
    ```python title="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()
    ```
  </Tab>
  <Tab title="Flask">
    ```python title="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())
    ```
  </Tab>
</Tabs>

## 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:

1. Navigate to your Stack Auth dashboard
2. Go to the **Apps** section
3. Find and click on **API Keys** in the app store
4. Click the **Enable** button

Once enabled, you can configure User API Keys and Team API Keys in the app settings. The app will provide your users with a prebuilt UI to manage their own API keys.

## 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.

<Tabs>
  <Tab title="Next.js">
    ```typescript title="app/src/account-page.tsx"
    import { AccountSettings } from '@stackframe/stack';

    export default function MyAccountPage() {
      return (
        <AccountSettings
          fullPage={true}
        />
      );
    }
    ```
  </Tab>
  <Tab title="React">
    ```typescript title="app/src/account-page.tsx"
    import { AccountSettings } from '@stackframe/react';

    export default function MyAccountPage() {
      return (
        <AccountSettings
          fullPage={true}
        />
      );
    }
    ```
  </Tab>
</Tabs>

### 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
- `allowTeamApiKeys` is configured in your project settings
- The user has the `$manage_api_keys` permission for the team

Users with appropriate permissions can manage team API keys directly from the team settings interface.

## Working with API Keys

### Creating User API Keys

<Tabs>
  <Tab title="Next.js Client">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Next.js Server">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="React">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Django">
    ```python title="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())
    ```
  </Tab>
  <Tab title="FastAPI">
    ```python title="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()
    ```
  </Tab>
  <Tab title="Flask">
    ```python title="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())
    ```
  </Tab>
</Tabs>

### Creating Team API Keys

<Tabs>
  <Tab title="Next.js Client">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Next.js Server">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="React">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Django">
    ```python title="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())
    ```
  </Tab>
  <Tab title="FastAPI">
    ```python title="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()
    ```
  </Tab>
  <Tab title="Flask">
    ```python title="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())
    ```
  </Tab>
</Tabs>

### Listing API Keys

<Tabs>
  <Tab title="Next.js Client">
    ```typescript title="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>
      );
    }
    ```
  </Tab>
  <Tab title="Next.js Server">
    ```typescript title="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>
      );
    }
    ```
  </Tab>
  <Tab title="React">
    ```typescript title="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>
      );
    }
    ```
  </Tab>
  <Tab title="Django">
    ```python title="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)
    ```
  </Tab>
  <Tab title="FastAPI">
    ```python title="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()
    ```
  </Tab>
  <Tab title="Flask">
    ```python title="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())
    ```
  </Tab>
</Tabs>

### Revoking API Keys

API keys can be revoked when they are no longer needed or if they have been compromised.

<Tabs>
  <Tab title="Next.js Client">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Next.js Server">
    ```typescript title="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();
      }
    }
    ```
  </Tab>
  <Tab title="React">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Django">
    ```python title="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'})
    ```
  </Tab>
  <Tab title="FastAPI">
    ```python title="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"}
    ```
  </Tab>
  <Tab title="Flask">
    ```python title="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'})
    ```
  </Tab>
</Tabs>

### Checking API Key Validity

You can check if an API key is still valid:

<Tabs>
  <Tab title="Next.js Client">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Next.js Server">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="React">
    ```typescript title="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>;
    }
    ```
  </Tab>
  <Tab title="Django">
    ```python title="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})
    ```
  </Tab>
  <Tab title="FastAPI">
    ```python title="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}
    ```
  </Tab>
  <Tab title="Flask">
    ```python title="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})
    ```
  </Tab>
</Tabs>
