# auth.md

LookLinker lets fashion brands, boutiques, stores, and retail teams reserve short URLs and manage interactive shortlinker pages. Agents can discover public endpoints directly and should use human-delegated authentication for protected dashboard, page editing, invitation, and account workflows.

Resource server: https://looklinker.com
Authorization server: https://looklinker.com
Upstream session issuer: https://bxxlsqosmryasocvdjrd.supabase.co/auth/v1

## Step 1 - Discover

Fetch the Protected Resource Metadata first, then follow its authorization server entry to the OAuth Authorization Server metadata. The Authorization Server metadata contains the agent_auth block.

- Protected Resource Metadata: https://looklinker.com/.well-known/oauth-protected-resource
- Authorization Server metadata: https://looklinker.com/.well-known/oauth-authorization-server
- OpenID configuration: https://looklinker.com/.well-known/openid-configuration
- API catalog: https://looklinker.com/.well-known/api-catalog
- OpenAPI description: https://looklinker.com/openapi.json
- MCP server card: https://looklinker.com/.well-known/mcp/server-card.json
- Agent skills: https://looklinker.com/.well-known/agent-skills/index.json

~~~http
GET /.well-known/oauth-protected-resource HTTP/1.1
Host: looklinker.com
Accept: application/json
~~~

~~~json
{
  "resource": "https://looklinker.com",
  "authorization_servers": ["https://looklinker.com"],
  "scopes_supported": ["openid", "email", "profile", "pages:read", "pages:write", "slugs:write", "invitations:write", "requests:read", "leads:read"],
  "bearer_methods_supported": ["header"]
}
~~~

## Step 2 - Pick A Method

LookLinker supports service_auth for agents acting with a human user and advertises identity_assertion for ID-JAG-aware agents that can prove a user identity to the LookLinker audience. If the agent cannot produce an ID-JAG, use service_auth.

Supported identity types: service_auth, identity_assertion
Supported credential type: Supabase session JWT

Public signup, slug suggestion, slug availability, and contact lead endpoints can be used without user delegation when endpoint validation and rate limits are satisfied.

## Step 3 - Register

For human-delegated access, direct the user to LookLinker's registration or login surface. Accepted brands and boutiques receive access to the creator dashboard after approval.

~~~json
{
  "type": "service_auth",
  "login_hint": "user@example.com"
}
~~~

Expected service_auth response shape:

~~~json
{
  "registration_id": "looklinker_user_session",
  "registration_type": "service_auth",
  "claim_url": "https://looklinker.com/login",
  "claim_token": "user-owned-browser-session",
  "claim_token_expires": "session",
  "post_claim_scopes": ["openid", "email", "profile", "pages:read", "pages:write"],
  "claim": {
    "user_code": "browser-login",
    "expires_in": 600,
    "verification_uri": "https://looklinker.com/login",
    "interval": 5
  }
}
~~~

Agents should never ask users to paste long-lived service-role credentials or BUREAU bearer tokens. Server-to-server invitation issuance uses approved server credentials only and those credentials must stay outside browser, prompt, and client contexts.

For identity_assertion, submit an ID-JAG assertion for the LookLinker audience. If the asserted identity maps to an existing accepted account, LookLinker may require the same browser claim ceremony before protected access is used.

~~~json
{
  "type": "identity_assertion",
  "assertion": "<id-jag>"
}
~~~

## Step 4 - Claim Ceremony

The user completes the claim by signing in at https://looklinker.com/login with the same email address used for the accepted LookLinker request. Once signed in, the user can finish onboarding, choose or confirm the reserved slug, and publish the page.

Agents should treat the browser login as a user-owned step. Do not collect passwords, one-time codes, Supabase refresh tokens, or session cookies from the user.

Poll or retry credential exchange only after the user has completed the browser login.

~~~http
POST /oauth2/token HTTP/1.1
Host: looklinker.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:workos:agent-auth:grant-type:claim&claim_token=user-owned-browser-session
~~~

While the user has not completed login, treat the state as authorization_pending. If the login expires, restart registration.

## Step 5 - Use The Credential

Protected API calls use a bearer token from the user's authenticated LookLinker session.

~~~http
Authorization: Bearer <supabase-session-jwt>
~~~

Available protected scopes include pages:read, pages:write, slugs:write, invitations:write, requests:read, and leads:read. Use the OpenAPI document for endpoint-specific requirements.

## Errors

- unauthenticated: redirect the user to https://looklinker.com/login.
- pending_approval: the LookLinker request has not been accepted yet.
- setup_incomplete: the page is reserved but the user has not finished onboarding.
- insufficient_scope: request a user session with the required dashboard permissions.
- rate_limited: retry later with backoff.

## Revocation

Users can revoke browser sessions by signing out of LookLinker. Server-to-server credentials must be rotated in the deployment environment. Agents must discard cached bearer tokens after sign-out, user revocation, expiry, or any 401 response.
