---
title: How Auth0 is integrated
description: Resource servers, clients, grants, and tenant settings.
sidebar:
  order: 1
  label: Overview
---

Auth0 issues every access token the shop accepts, except the signed-out Poppy Session Tokens the Auth0 proxy signs itself. Terraform owns the declared tenant infrastructure; runtime and owner-managed objects are listed below.

**[Resource servers](/architecture/auth0/resource-servers)**

The Shop API and MCP identifiers, scopes and subject-type policies.

**[Clients and grants](/architecture/auth0/clients-and-grants)**

Website, storefront, backoffice, agent forwarder and MCP clients, and exactly what each may request.

**[Token exchange](/architecture/auth0/token-exchange)**

On-Behalf-Of versus Custom Token Exchange, and `act` chains.

**[My Account](/architecture/auth0/my-account)**

Web-only My Account, multi-resource refresh tokens and step-up.

**[Actions](/architecture/auth0/actions)**

Account-security Actions and their audience allowlists.

**[Terraform map](/architecture/auth0/terraform)**

Where each object lives in the repository and the tests that pin it.

## Resource ownership

- **Terraform:** the declared APIs, shared clients, grants, connections, Actions and opted-in tenant settings.
- **Proxy Auth0:** per-agent applications created and maintained at runtime. MCP clients can also register through DCR.
- **Tenant owner:** activation and policy checks for the built-in My Account API, manual CIMD registration, and the
  platform registrations required by [invited agents](/architecture/auth0/invited-agents). A Terraform apply does not
  perform these prerequisites.

Keep these owners distinct when reviewing drift or adopting an existing tenant.

## Principles

- **Access is granted per client, not per tenant.** The Shop API and MCP resources use client-grant-required policies.
  Each caller gets an explicit grant listing exactly its scopes.
- **Human-only scopes are never granted to the MCP client**, and the guest and operator scopes are never granted to
  user flows.
- **Tokens use the RFC 9068 profile**, so every access token carries `client_id` and `typ: at+jwt`.
- **Shop API and MCP identifiers have no trailing slash.** Set them to your exact HTTPS resource origins.
  `https://api.tarnandtimber.com` and `https://mcp.tarnandtimber.com` are the existing deployment's examples.
  The built-in My Account identifier is different: it ends in `/me/` (see [My Account](/architecture/auth0/my-account)).

## Issuer and keys

Access tokens carry the custom-domain issuer. That host is served by the Auth0 proxy, which is also an authorization
server and signs its own tokens. If the API took signing keys from that host, any key the Auth0 proxy publishes there
could mint tokens the API accepts. The verifiers in the API and MCP server therefore fetch Auth0 keys from the
**tenant domain** and check the issuer against the custom domain. Proxy Auth0 Session Tokens verify only against the
Auth0 proxy's own keys, so neither key set can stand in for the other (see
[Poppy agents](/architecture/request-flows/poppy-agents#signed-out-rest)).

## Tenant settings for MCP

- Dynamic Client Registration is enabled so MCP clients can register themselves.
- The resource parameter profile is `compatibility`, because MCP clients send `resource=` rather than `audience=`.
- Dynamic clients can only use domain-level connections, so the Poppy-Users database connection is made a domain
  connection.
- New clients are third-party and strict: PKCE, consent, authorization code and refresh token only. They reach an API
  only through an explicit grant.
