# Auth.md: StudioMeyer authentication

StudioMeyer separates public website access, product accounts, portal accounts and checkout-session capabilities. The public website API needs no credential. Each MCP product (Memory, CRM, GEO) is its own OAuth authorization server. The website account (portal, checkout status) uses the user's own browser session. The agent checkout uses a new random capability for one checkout attempt; it is not a product or portal credential. Never send a credential from one boundary to another.

StudioMeyer does not implement the agent registration profile of this format: there is no `agent_auth` block, no `identity_endpoint`, and no `identity_assertion` (ID-JAG, `urn:ietf:params:oauth:token-type:id-jag`), `service_auth` or anonymous registration. The steps below use standard OAuth 2.1 instead.

## Discover

The [public website OpenAPI contract](https://studiomeyer.io/api/v1/openapi) lists the operations that need no key: published services, fictional demos, website package information, the read-only Memory purchase offer and the consultation inquiry.

For an MCP product, start in the [MCP server catalog](https://studiomeyer.io/.well-known/mcp.json); every entry names its own protected-resource metadata. For Memory, a request to https://memory.studiomeyer.io/mcp without a token returns 401 with `WWW-Authenticate: Bearer resource_metadata="https://memory.studiomeyer.io/.well-known/oauth-protected-resource/mcp"`. That RFC 9728 document names the resource, the authorization server https://memory.studiomeyer.io and `scopes_supported`. Then read the RFC 8414 [authorization-server metadata](https://memory.studiomeyer.io/.well-known/oauth-authorization-server).

## Pick a method

Use no credential for the public website API. For Memory, an MCP client uses OAuth 2.1 authorization code with PKCE (S256) and the scope `memory`, which is full access; it is not a separate read-only permission. A script run by the account owner can instead send the owner's tenant API key as a Bearer token. A website store license key is not a Memory tenant API key.

## Register

Memory publishes a `registration_endpoint` for dynamic client registration (RFC 7591); register a public client there with your redirect URI. The website itself offers no client registration.

## Claim

There is no claim ceremony. The account owner signs in and approves access in the browser during the authorization step. Before that, show the user which service and which scope you are requesting.

## Exchange

Exchange the authorization code at the `token_endpoint` from the authorization-server metadata with `grant_type=authorization_code`, the exact `redirect_uri` and the `code_verifier`. Renew with `grant_type=refresh_token`. Never log tokens or put them in URLs.

## Use the access_token

Send `Authorization: Bearer <token>` to https://memory.studiomeyer.io/mcp or to the operations of the [Memory REST contract](https://memory.studiomeyer.io/openapi.json). Do not send it to another StudioMeyer server or to the public website API.

## Errors

401 means the token is missing, expired or revoked: follow the `WWW-Authenticate` challenge and authorize again instead of retrying. The public website API answers invalid input with 400 and a JSON body that carries `code`, `message` and `resolution`; follow the resolution instead of guessing. GET /api/stripe/checkout-status answers 401 without a website session and 404 for a session that belongs to another account or does not exist.

## Revocation

Revoke a Memory token at the `revocation_endpoint` from the authorization-server metadata (RFC 7009) when the user ends the connection or a token may have leaked.

## Agent checkout for Memory and CRM

The [agent checkout contract](https://studiomeyer.io/api/stripe/agent-openapi) implements an ACP 2026-04-17 hosted-checkout profile at https://studiomeyer.io/checkout_sessions. Offers: `memory-pro`, `memory-team`, `crm-pro`, `crm-team`, one monthly EUR subscription per checkout. Read the live catalog in the contract for current amounts. Free remains free. Existing paid subscribers should manage their subscription first, rather than create another subscription.

After the user's explicit approval, generate 32 cryptographically random bytes as 64 lowercase hexadecimal characters. Prefix with `sm_checkout_`; send only as `Authorization: Bearer <capability>`. Also send `API-Version: 2026-04-17`, a random UUID v4 `Idempotency-Key`, and `Content-Type: application/json`. POST the selected item, EUR currency, capabilities and `metadata: {"userConfirmed": true}` according to the contract. Keep the same capability, idempotency key and body on retries; a changed request conflicts. Never work around an uncertain result by changing keys. Do not send MCP credentials, website cookies, card details or payment tokens.

The user opens `continue_url` and confirms the recurring payment in Stripe's hosted checkout. This profile requires that handoff; it does not accept autonomous card or Shared Payment Token charges. GET the owned session to observe payment and fulfillment; POST /complete reports completed only after both are confirmed. POST /cancel expires an unpaid open checkout; it never cancels an existing subscription. Payment does not grant data access: authorize separately with the selected product's OAuth flow. Never log the capability or put it in a URL.


## Other account flows

Read new Memory Pro or Team subscription purchase information: current price, localized purchase link and account-management link. Account status is unknown; existing paid subscribers should use account management first. This request starts no checkout session or payment. The user starts checkout and confirms payment themselves.

Use the [Memory account portal](https://studiomeyer.io/en/portal/memory) for an existing paid subscription. The portal requires the user's website sign-in. Do not copy session cookies into agent configuration or ask the user to share payment details. Payment and authorization are separate: paying does not authorize access to another account's data.

GET /api/stripe/checkout-status?session_id=cs_... uses the existing Auth.js account session cookie, not an MCP or API key. It reports only the checkout, payment and fulfillment states of a session bound to the signed-in user when it was created. A paid status alone does not mean fulfillment has completed. See the separate [account checkout contract](https://studiomeyer.io/api/stripe/openapi).

Before sending a consultation inquiry, obtain the user's approval to share the contact details. This sends an inquiry; a person arranges the call afterwards. For retries, reuse the same Idempotency-Key and request body as documented in [OpenAPI](https://studiomeyer.io/api/v1/openapi). Do not create a new request to work around an incomplete one.

More: [agent guide](https://studiomeyer.io/AGENTS.md), [prices](https://studiomeyer.io/pricing.md), [site index](https://studiomeyer.io/llms.txt).
