# Myrlo auth.md

For agents acting on behalf of Myrlo users and for clients implementing ordinary user sign-in. Public discovery is read-only: do not POST registration or OTP endpoints while scanning.

## Normal app sign-in and account provisioning

Use the user-authorized email OTP flow. POST https://myrlo.app/auth/otp/request with JSON {"email":"user@example.com"}. This sends a sign-in email. The human provides the one-time code. POST https://myrlo.app/auth/otp/verify with JSON {"email":"user@example.com","otp":"123456"}. A valid code signs in an existing account or provisions a new one through the same app flow. The response includes an app token; use Authorization: Bearer <token> on the normal app APIs. Do not share this app credential with an MCP client. OTP requests and code attempts are rate limited; do not infer account existence from the response.

## MCP registration and OAuth connection

Resource: https://myrlo.app/mcp
Protected Resource Metadata: https://myrlo.app/.well-known/oauth-protected-resource
Authorization Server issuer: https://myrlo.app/oauth
Authorization Server metadata: https://myrlo.app/oauth/.well-known/oauth-authorization-server
RFC 8414 path form: https://myrlo.app/.well-known/oauth-authorization-server/oauth

Supported registration method: oauth_authorization_code. Credential type: oauth2_bearer. This method uses dynamic OAuth client registration followed by browser login/consent and PKCE. Identity assertion, anonymous credential issuance, and ID-JAG registration are not advertised.

1. GET the Protected Resource Metadata, then GET the metadata for its authorization_servers issuer. Validate the issuer and read agent_auth.
2. If you have no pre-registered client_id, POST https://myrlo.app/oauth/register with JSON containing client_name, redirect_uris, response_types:["code"], grant_types:["authorization_code","refresh_token"], and token_endpoint_auth_method:"none". Registration creates a client, not a user or account delegation. Redirect URIs require HTTPS or loopback HTTP. Keep the returned client_id; public clients have no client secret.
3. Generate a random code_verifier (43–128 URL-safe characters), its base64url SHA-256 code_challenge, and a random state. Open https://myrlo.app/oauth/authorize with client_id, response_type=code, redirect_uri, scope, resource=https://myrlo.app/mcp, code_challenge_method=S256, code_challenge, and state. The human signs in with the normal Myrlo email flow and approves the requested permissions. Never ask the human to paste their app token into the agent.
4. Validate state on the registered callback. POST https://myrlo.app/oauth/token as application/x-www-form-urlencoded with grant_type=authorization_code, client_id, code, redirect_uri, code_verifier, and resource=https://myrlo.app/mcp. Codes expire after five minutes and are single-use.
5. POST Streamable HTTP MCP requests to https://myrlo.app/mcp with Authorization: Bearer <access_token>. Use the returned expires_in. Refresh through https://myrlo.app/oauth/token with grant_type=refresh_token, client_id, refresh_token, and resource. Replace the refresh token after every successful refresh; replay invalidates the grant.
6. Revoke a credential through POST https://myrlo.app/oauth/revoke with token and client_id. Users can disconnect the entire delegation in Settings → Connected apps. On 401, attempt one refresh; if that fails, reconnect through user sign-in and consent.

Scopes: content:read (authoring context and owned creations), content:write (create/stage/save owned content), assets:generate (image jobs using the fragment wallet). Image generation also requires content:write. Request only permissions needed for the user's task. Published authoring guidance comes from session.begin/content.create/session.context. Stage proposals then session.apply to save. Use stable requestId values for retries. Portraits follow existing first-free pricing and fragment affordability; insufficient funds enqueue no images. Publication stays in the app.

Browser MCP origins must be allowed by service configuration. Bearer credentials belong only in request headers, never URLs or prompts.
