---
$schema: https://workos.com/auth-md/schema.json
agent_auth:
  skill: https://galaxy-fasteners.com/auth.md
  register_uri: https://api.sokisoko.com/oauth/register
  authorization_uri: https://api.sokisoko.com/oauth/authorize
  token_uri: https://api.sokisoko.com/oauth/token
  revocation_uri: https://api.sokisoko.com/oauth/revoke
  jwks_uri: https://api.sokisoko.com/.well-known/jwks.json
  identity_types_supported:
    - human_delegated
    - identity_assertion
  credential_types_supported:
    - oauth2_access_token
    - api_key
  code_challenge_methods_supported:
    - S256
  token_endpoint_auth_methods_supported:
    - none
  scopes_supported:
    - catalog:read
    - pricing:read
    - cart:write
    - orders:read
    - quotes:read
    - quotes:write
    - profile:read
---

# auth.md

How an autonomous agent gets credentials for the Galaxy Fasteners storefront API
and uses them.

There are two ways in, for two different jobs:

1. **OAuth 2.1, for an agent acting for a buyer.** Register yourself, send the buyer
   through consent at their own store, and get a scoped token for the MCP endpoint.
   No human has to paste a secret anywhere. This is the path MCP clients take.
2. **An API key, for the tenant's own back-office automation.** Minted by a tenant
   admin, `admin` audience, bounded by that admin's permissions.

The OAuth surface is enabled per deployment: if `POST /oauth/register` answers 404 on
the platform you're targeting, it isn't live there yet — use an API key instead.

- **Authorization server:** `https://api.sokisoko.com`
  ([metadata](https://galaxy-fasteners.com/.well-known/oauth-authorization-server))
- **Protected resource:** `https://api.sokisoko.com/mcp`, reachable — and
  requestable as a resource identifier — at `https://galaxy-fasteners.com/mcp`
  ([metadata](https://galaxy-fasteners.com/.well-known/oauth-protected-resource))
- **MCP server card:** [`/.well-known/mcp/server-card.json`](https://galaxy-fasteners.com/.well-known/mcp/server-card.json)
- **Store guide:** [`/llms.txt`](https://galaxy-fasteners.com/llms.txt)
- **OpenAPI description:** [`/openapi.json`](https://galaxy-fasteners.com/openapi.json)

## agent_auth

```json
{
  "agent_auth": {
    "skill": "https://galaxy-fasteners.com/auth.md",
    "register_uri": "https://api.sokisoko.com/oauth/register",
    "authorization_uri": "https://api.sokisoko.com/oauth/authorize",
    "token_uri": "https://api.sokisoko.com/oauth/token",
    "revocation_uri": "https://api.sokisoko.com/oauth/revoke",
    "jwks_uri": "https://api.sokisoko.com/.well-known/jwks.json",
    "identity_types_supported": ["human_delegated", "identity_assertion"],
    "credential_types_supported": ["oauth2_access_token", "api_key"],
    "code_challenge_methods_supported": ["S256"],
    "token_endpoint_auth_methods_supported": ["none"],
    "scopes_supported": [
      "catalog:read", "pricing:read", "cart:write",
      "orders:read", "quotes:read", "quotes:write", "profile:read"
    ]
  }
}
```

Identity is **human-delegated**: every token traces to one buyer who approved it and
can revoke it. There is no anonymous or self-asserted agent identity — an agent acts
for someone, or not at all.

## Complete standalone registration flow

Register your agent via the OAuth 2.1 authorization code flow with PKCE. Public
clients only — no client secrets, no implicit grant, no password grant. Every token
traces to a human buyer who approved it.

### Register the client

Send a POST to the registration endpoint with your agent's metadata:

```
POST https://api.sokisoko.com/oauth/register
Content-Type: application/json

{
  "client_name": "Acme Procurement Assistant",
  "redirect_uris": ["http://127.0.0.1:7777/callback"],
  "scope": "catalog:read pricing:read orders:read quotes:write",
  "token_endpoint_auth_method": "none"
}
```

Response includes a `client_id`. Store it — you send this on every authorize
request. Redirect URIs must be `https`, a loopback `http` address, or a
private-use scheme.

### Authorize the buyer

Send the buyer to the authorization endpoint:

```
GET https://api.sokisoko.com/oauth/authorize
  ?response_type=code
  &client_id=sok_…
  &redirect_uri=http://127.0.0.1:7777/callback
  &scope=catalog:read+pricing:read
  &resource=https://api.sokisoko.com/mcp
  &store=galaxy-fasteners.com
  &state=…
  &code_challenge=…&code_challenge_method=S256
```

The buyer signs in at their own store and sees exactly what your agent asked for.
`code` is returned as a query parameter on the redirect URI. Declining returns
`error=access_denied`.

### Exchange the code

Single-use code with a 60-second lifetime:

```
POST https://api.sokisoko.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=…&code_verifier=…
&client_id=sok_…&redirect_uri=http://127.0.0.1:7777/callback
```

Returns an access token (15 min) and a refresh token (30 days, rotating).

### Call the API

Include the access token as a Bearer header:

```http
Authorization: Bearer <access_token>
```

Access tokens are ES256 JWTs verifiable against the
[JWKS](https://api.sokisoko.com/.well-known/jwks.json), and audience-bound to the
`resource` you asked for — a token minted for one resource is refused at another.

Revoke with `POST /oauth/revoke` (`token=<refresh token>`); buyers can also
disconnect an agent through their account's agents API
(`GET` / `DELETE /storefront/account/agents`).

## Audience

Three token audiences, and a token is rejected outside its own:

| Audience     | Who it represents                | Route prefix   |
| ------------ | -------------------------------- | -------------- |
| `admin`      | Tenant staff and their agents    | `/admin/*`     |
| `storefront` | A buyer at a tenant's store      | `/storefront/*` |
| `vendor`     | A marketplace seller             | `/vendor/*`    |

API keys carry the `admin` audience. An agent acting **on behalf of a buyer** signs in
as that buyer instead (`POST /storefront/auth/login`) and gets a `storefront` token.

## Registration / provisioning

Keys are provisioned in the admin console, not over the wire:

1. A tenant admin signs in at `https://admin.sokisoko.com`.
2. **Integrations → API keys → New key.** They name the key, pick its scopes, and
   optionally set an expiry (RFC 3339; omit for no expiry).
3. The raw secret is shown **once**, at creation: `tgk_` followed by 64 hex
   characters. It is not retrievable afterwards — only the first 12 characters are
   ever displayed again, so a key can be recognised but not reconstructed.
4. Hand that secret to the agent through your own secret store. Do not embed it in
   prompts, source, or anything a model provider retains.

If your agent needs to walk an operator through this, link them straight to
`https://admin.sokisoko.com/api-keys`.

**Scope ceiling:** a key can never exceed the permissions of the admin who created it.
Ask for the narrowest set that does the job — `catalog:read` for a catalog reader,
`quotes:write` for a quoting agent. The full list is `scopes_supported` in
[the resource metadata](https://galaxy-fasteners.com/.well-known/oauth-protected-resource).
