# auth.md

Expedition Insure supports customer-authorized AI agents through OAuth 2.1. The protected identity resource is `https://auth.expedition.insure/identity`; customer authorization is isolated at `https://auth.expedition.insure`.

## 1. Discover

Fetch [the protected resource metadata](https://expedition.insure/.well-known/oauth-protected-resource), then fetch [the advertised authorization server metadata](https://auth.expedition.insure/.well-known/oauth-authorization-server).

The protected resource accepts bearer credentials in the `Authorization` header. Available scopes are:

- `identity:read`: read the customer's stable Expedition Insure subject.
- `profile:read`: read the customer's display name.
- `email:read`: read the customer's verified email and `email_verified` status.

## 2. Pick a method

Use OAuth authorization code with S256 PKCE. This service requires the customer to sign in with Expedition Insure's existing Google or email-OTP authentication and give explicit consent in their browser.

Direct ID-JAG, anonymous, and `service_auth` claim-token registration are not accepted. Do not send an external identity assertion or a user's password or OTP to the agent endpoints.

## 3. Register the OAuth client

Register dynamically with RFC 7591:

```http
POST https://auth.expedition.insure/register
Content-Type: application/json

{
  "client_name": "Example customer agent",
  "redirect_uris": ["https://agent.example/oauth/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"]
}
```

Keep the returned `client_id`. Confidential clients must also protect their returned `client_secret`.

The authorization server's `agent_auth.register_uri` is this client-registration endpoint. Its `agent_auth.claim_uri` is the browser authorization endpoint at `https://auth.expedition.insure/authorize`, where the signed-in customer claims the verified identity and approves the requested scopes.

Redirect URIs must be absolute, fragment-free HTTPS URLs. Native CLI clients may use HTTP only with a literal `127.0.0.0/8` or `[::1]` loopback address; the authorization request may choose a dynamic port for the same registered loopback path. Fragments, credentials, `localhost`, non-loopback HTTP, and custom/private-use schemes are rejected. The client name is self-asserted and unverified; the customer consent screen also shows the registered client ID and exact redirect origin.

## 4. Authorize and claim the verified identity

Generate a PKCE verifier and its SHA-256 challenge. Open this URL for the customer:

```text
https://auth.expedition.insure/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=ENCODED_REDIRECT_URI&state=OPAQUE_CLIENT_STATE&scope=identity%3Aread%20profile%3Aread%20email%3Aread&code_challenge=BASE64URL_SHA256_CHALLENGE&code_challenge_method=S256
```

The customer signs in on `expedition.insure`, reviews the requested identity fields, and authorizes or declines the connection. Declining sends `access_denied` with the original `state` to the registered redirect URI and never issues a code. Authorizing redirects to the registered `redirect_uri` with `code` and the original `state`. The authorization code is short-lived and single-use.

Exchange it at the token endpoint:

```http
POST https://auth.expedition.insure/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&client_id=CLIENT_ID&code=AUTHORIZATION_CODE&redirect_uri=ENCODED_REDIRECT_URI&code_verifier=PKCE_VERIFIER
```

## 5. Use the credential

Present the returned access token as a bearer credential:

```http
GET https://auth.expedition.insure/identity
Authorization: Bearer ACCESS_TOKEN
```

The response always includes `sub`. It includes `name` when `profile:read` was granted and `email` plus `email_verified: true` when `email:read` was granted. The values come from the customer account that completed the browser authorization; registration never trusts a client-supplied email.

## 6. Refresh and revoke

Use `grant_type=refresh_token` at `https://auth.expedition.insure/token` while the refresh token remains valid. Revoke an access or refresh token at the same endpoint using the RFC 7009 `token` form parameter and applicable client authentication. Drop revoked credentials and restart discovery if authorization is needed again.

## 7. Errors

- `invalid_request`: correct the authorization parameters; S256 PKCE and `identity:read` are required.
- `invalid_client`: register again or correct client authentication.
- `invalid_grant`: discard the code or refresh token and restart authorization.
- `access_denied`: the customer declined, the verified customer grant expired, or identity verification failed.
- `insufficient_scope`: request the required scope and obtain fresh consent.
- HTTP 401: follow the `WWW-Authenticate` resource-metadata link and restart discovery.

Privacy: https://expedition.insure/privacy

Terms: https://expedition.insure/terms

Integration support: help@expedition.insure
