---
title: API keys
description: Create, list, rotate, and revoke machine-scoped API keys with convex-auth.
sidebar:
  order: 10
---

`convex-auth` has a native `api_keys` table and a set of helpers for creating, hashing, verifying, and rotating API keys. The `@vortex-api/convex-auth/react` package ships `useConvexApiKeys`, `ConvexApiKeyCreated`, and the lower-level `ConvexApiKeyCreateForm` and `ConvexApiKeyList` components.

## How it works

- API keys are scoped to a user and an active organization.
- The full token is returned once on creation or rotation. Only a hash and prefix are stored.
- Keys carry scopes, an optional expiration, and optional IP allowlist ranges.
- The `useConvexApiKeys` hook wires a consumer Convex API to the presentational components.

## Mount the API keys component

If you need service/API-key authentication, mount the `apiKeys` component alongside the core component:

```ts convex/convex.config.ts
import { defineApp } from "convex/server";
import { v } from "convex/values";
import authCore from "@vortex-api/convex-auth/convex.config/core";
import authApiKeys from "@vortex-api/convex-auth/convex.config/apiKeys";

const app = defineApp({
  env: {
    JWT_PRIVATE_KEY: v.string(),
    JWKS: v.string(),
  },
});

app.use(authCore, {
  env: {
    JWT_PRIVATE_KEY: app.env.JWT_PRIVATE_KEY,
    JWKS: app.env.JWKS,
  },
});

app.use(authApiKeys, {
  env: {
    JWT_PRIVATE_KEY: app.env.JWT_PRIVATE_KEY,
    JWKS: app.env.JWKS,
  },
});

export default app;
```

## Consumer functions

Add queries and mutations in your own `convex/` directory that call the component and map to public client shapes. The example app uses:

- `api.apiKeys.listMyApiKeys` — list active keys for the active organization.
- `api.apiKeys.createApiKey` — issue a new key and return the one-time token.
- `api.apiKeys.revokeApiKey` — revoke a key.
- `api.apiKeys.rotateApiKey` — issue a replacement and revoke the old key.

## React hooks and components

### `useConvexApiKeys`

```tsx src/ApiKeys.tsx
import { useConvexApiKeys, ConvexApiKeyCreated } from "@vortex-api/convex-auth/react";
import { api } from "../convex/_generated/api";

const SCOPES = ["read", "write", "delete"] as const;

export function ApiKeys() {
  const { formProps, listProps, created, clearCreated } = useConvexApiKeys(api, {
    scopeOptions: SCOPES,
  });

  return (
    <>
      <ConvexApiKeyCreateForm {...formProps} />
      {created && <ConvexApiKeyCreated apiKey={created.apiKey} onClose={clearCreated} />}
      <ConvexApiKeyList {...listProps} />
    </>
  );
}
```

The hook returns:

- `formProps` — ready for `ConvexApiKeyCreateForm`.
- `listProps` — ready for `ConvexApiKeyList`.
- `created` — the one-time `{ apiKey, apiKeyId, keyPrefix, keyStart }` after a successful create or rotate.
- `clearCreated` — a callback to dismiss the created token display.

### `ConvexApiKeyCreated`

Render this once, immediately after `create` or `rotate`, so the user can copy the plaintext token. The full token is not recoverable after this step.

```tsx
import { ConvexApiKeyCreated } from "@vortex-api/convex-auth/react";

<ConvexApiKeyCreated apiKey={created.apiKey} onClose={() => setCreated(null)} />;
```

## Server-side helpers

`@vortex-api/convex-auth/convex` re-exports the `machine` helpers you need to build `apiKeys` mutations and actions:

- `normalizeConvexApiKeyCreateInput` — turn a user payload into a validated create shape.
- `createConvexApiKeyCreateArgsValidator` — build the validator for your mutation.
- `deriveApiKeySecret` / `hashApiKeySecret` / `verifyApiKeySecret` — generate and verify the secret token.
- `requireActiveApiKeyRecord` — resolve an API key from a secret in a request.
- `resolveApiKeyRecordStatus` — check active, expired, revoked, or disabled status.

These run inside Convex actions because they need `crypto.subtle` and other non-deterministic work. The component's `api_keys` table stores only the hash, prefix, scopes, and metadata.

> **Warning**
>
> Treat the plaintext `apiKey` returned from `createApiKey` and `rotateApiKey` as a secret. Show it
> once, copy it to the user's clipboard, and do not persist it in logs, local storage, or URL
> parameters.
