Skip to content
v3.0.1 — MCP OAuth, organizations, passkeys, SSR adaptersChangelog
Convex Auth
Esc
↑↓navigate↵open⌘Jpreview
On this page

Service principals

Create and manage machine identities and service-owned API keys with convex-auth.

convex-auth supports service principals: machine identities with their own permissions that can own API keys and act on your backend. The @vortex-api/convex-auth/react package ships useConvexServicePrincipals, which wires a consumer Convex API to a create form and list.

How it works

  • Service principals live in the service_principals component table.
  • Each principal has a key, name, description, status (active or disabled), and permissions.
  • A principal is scoped to an organization.
  • You can associate service-owned API keys with a principal so the principal’s permissions can be enforced at request time.

Mount the service principals component

Mount the servicePrincipals component alongside the core and apiKeys components:

import { defineApp } from "convex/server";
import { v } from "convex/values";
import authCore from "@vortex-api/convex-auth/convex.config/core";
import authServicePrincipals from "@vortex-api/convex-auth/convex.config/servicePrincipals";

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(authServicePrincipals, {
  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. The example app uses:

  • api.servicePrincipals.listMyServicePrincipals — list principals for the active organization.
  • api.servicePrincipals.createServicePrincipal — create a new principal.
  • api.servicePrincipals.updateServicePrincipal — update name, description, or permissions.
  • api.servicePrincipals.setServicePrincipalStatus — enable or disable a principal.

React hook

useConvexServicePrincipals

import { useConvexServicePrincipals } from "@vortex-api/convex-auth/react";
import { api } from "../convex/_generated/api";

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

export function ServicePrincipals() {
  const {
    servicePrincipals,
    state,
    creating,
    onKeyChange,
    onNameChange,
    onDescriptionChange,
    onPermissionsChange,
    onSubmit,
    onStatusChange,
  } = useConvexServicePrincipals(api, { permissionOptions: PERMISSIONS });

  return (
    <>
      <ServicePrincipalCreateForm
        state={state}
        creating={creating}
        onKeyChange={onKeyChange}
        onNameChange={onNameChange}
        onDescriptionChange={onDescriptionChange}
        onPermissionsChange={onPermissionsChange}
        onSubmit={onSubmit}
      />
      <ServicePrincipalList servicePrincipals={servicePrincipals} onStatusChange={onStatusChange} />
    </>
  );
}

The hook returns:

  • servicePrincipals — the list from api.servicePrincipals.listMyServicePrincipals.
  • state — the current create-form state.
  • creating — whether a create is in flight.
  • onKeyChange, onNameChange, onDescriptionChange, onPermissionsChange — form change handlers.
  • onSubmit — creates a principal from the form state.
  • onStatusChange(servicePrincipalId, status) — enables or disables a principal.

Service-owned API keys

Once a service principal is created, you can issue API keys owned by that principal. The consumer createApiKey can set the principal as the owner by passing servicePrincipalId (or letting the component’s issueServiceOwnedApiKey path handle it). A principal’s permissions are checked when the service-owned key is used to authorize a request.

Was this page helpful?