# Delegated authorization

Canonical: https://auggy.dev/docs/delegated-authorization
Status: Preview
Package: auggy 0.5.0

Advanced preview: bridge an existing app login into **Auggy** with short-lived assertions and route/tool requires rules.

## Boundary

> **Note: Advanced preview**
>
> Use this only when an existing application must authorize optional **Auggy** routes or protected tools. Keep the application's identity provider and authorization records as the source of truth.

Delegated authorization lets a **Supabase**, **Clerk**, Auth0-style, or custom app session call visitor.required routes and protected tools without making **Auggy** a general auth provider.

- The app verifies the user session and decides what the user may do.
- The app mints a compact, short-lived **Auggy** assertion.
- **Auggy** verifies the signature, audience, provider, key ID, TTL, and replay protection.
- **Auggy** enforces route-local and tool-local requires rules against assertion scopes and grants.
- Roles can travel as context, but roles do not satisfy authorization requirements.

> **Note: Team/internal users today**
>
> Staff and customers use public recognized identity with app-minted scopes and grants. People operating the **Auggy** instance use creator access. Per-operator console permissions are future work.

## Flow

1. Browser: Has a normal app login session.
2. Browser: Asks the app backend for an **Auggy** auth assertion.
3. App backend: Verifies the session with its trusted provider.
4. App backend: Derives minimal scopes and resource grants.
5. App backend: Signs a short-lived assertion.
6. Browser: Calls **Auggy** with x-auggy-auth-assertion.
7. Auggy: Resolves public recognized context and enforces route/tool requires before work runs.

## Mint assertions

**Server-side assertion helper**

```ts
import { createExternalAuthAssertion } from "auggy";

export async function mintAuggyAssertionForUser(user: {
  id: string;
  email?: string;
  orgId?: string;
  roles: string[];
}) {
  const grants = await delegatedGrantsForUser(user);

  return createExternalAuthAssertion({
    secret: process.env.AUGGY_EXTERNAL_AUTH_SECRET!,
    keyId: "2026-07",
    audience: "storefront-agent",
    provider: "custom",
    subject: user.id,
    ttlSeconds: 60,
    email: user.email,
    emailVerified: true,
    orgId: user.orgId,
    roles: user.roles,
    scopes: ["orders.read"],
    grants,
    authzVersion: "orders-v1",
    jti: crypto.randomUUID(),
  });
}
```

> **Warning: Server only**
>
> Never put AUGGY_EXTERNAL_AUTH_SECRET in browser code. The generated browser client can forward an assertion through authAssertion, but the app backend must create it.

## Route and tool requires

**Route requirement**

```ts
defineRoute.post("/orders/:id/refund", {
  auth: "visitor.required",
  params: z.object({ id: z.string() }),
  body: z.object({ reason: z.string() }),
  requires: { action: "refund.issue", resource: { param: "id" } },
  handler: ({ params }) => json({ refundId: "refund_123", orderId: params.id }),
});
```

**Tool requirement**

```ts
defineTool({
  name: "refund_order",
  description: "Refund a customer order.",
  category: "commerce",
  input: z.object({
    orderId: z.string(),
    reason: z.string(),
  }),
  requires: {
    action: "refund.issue",
    resource: { input: "orderId" },
  },
  execute: async ({ orderId }) => "refund-started:" + orderId,
});
```

## Related

- [Connect an application](https://auggy.dev/docs/connect-application/markdown)