# auth.md — Geolander Agent Registration

> You are an agent acting for a traveller or a Geolander operator. This file describes how to register an OAuth public client and obtain credentials for the protected Geolander Agent Reservation API.

Resource server: `https://geo-lander.com/wp-json/geolander-agent/v1/`  
Authorization server issuer: `https://geo-lander.com`  
Managed OAuth upstream: `https://jolly-sound-4ff2.cloudflareaccess.com`

The customer-facing website and public quote API require no account. The protected agent API uses Cloudflare Access Managed OAuth. There is no API-key flow and no anonymous access to protected resources. Passive scanners must not POST to the registration endpoint because registration creates persistent OAuth client state.

## Discovery

- OAuth protected resource metadata: https://geo-lander.com/.well-known/oauth-protected-resource
- OAuth authorization server metadata: https://geo-lander.com/.well-known/oauth-authorization-server
- A2A v1.0 Agent Card: https://geo-lander.com/.well-known/agent-card.json
- OpenAPI 3.1 specification: https://geo-lander.com/openapi.json
- Developer documentation: https://geo-lander.com/developers/

## Step 1 — Discover

Request a protected endpoint and read the `WWW-Authenticate: Bearer` header. Its `resource_metadata` parameter points to route-specific Cloudflare Protected Resource Metadata. The stable Geolander metadata above publishes `resource`, `authorization_servers`, `scopes_supported`, and `bearer_methods_supported`. Geolander exposes the single coarse scope `geolander.agent`, representing access to the protected agent API. Cloudflare binds authorization to the RFC 8707 `resource` value and evaluates the Access policy; it may return an empty OAuth `scope` string because permissions are enforced at the protected-resource boundary.

Fetch the authorization-server metadata and read its standard OAuth fields plus the `agent_auth` block. That block is the source of truth for the Auth.md skill, registration URI, claim URI, supported credential types, and revocation URI.

## Step 2 — Pick the supported method

Supported method: anonymous OAuth public-client registration followed by required user authentication. Anonymous means only that creating a `client_id` does not require an existing client credential; it never grants anonymous API access. The user must complete Cloudflare Access authentication before an `access_token` or `refresh_token` is issued.

- Registration endpoint: `POST https://jolly-sound-4ff2.cloudflareaccess.com/cdn-cgi/access/oauth/registration`
- Claim / user authorization endpoint: `https://jolly-sound-4ff2.cloudflareaccess.com/cdn-cgi/access/oauth/authorization`
- Credential types: `access_token`, `refresh_token`
- Credential presentation: `Authorization: Bearer <access_token>`
- Revocation endpoint: `POST https://jolly-sound-4ff2.cloudflareaccess.com/cdn-cgi/access/oauth/revoke`

### Machine-readable registration profile

The same complete registration method is embedded here so an agent can provision credentials even when it cannot parse OAuth metadata:

```json
{
  "agent_auth": {
    "skill": "https://geo-lander.com/auth.md",
    "register_uri": "https://jolly-sound-4ff2.cloudflareaccess.com/cdn-cgi/access/oauth/registration",
    "claim_uri": "https://jolly-sound-4ff2.cloudflareaccess.com/cdn-cgi/access/oauth/authorization",
    "revocation_uri": "https://jolly-sound-4ff2.cloudflareaccess.com/cdn-cgi/access/oauth/revoke",
    "identity_types_supported": ["anonymous"],
    "anonymous": {
      "credential_types_supported": ["access_token", "refresh_token"],
      "claim_uri": "https://jolly-sound-4ff2.cloudflareaccess.com/cdn-cgi/access/oauth/authorization",
      "requires_user_authentication": true
    }
  }
}
```

## Step 3 — Register the OAuth public client

Choose a localhost or loopback callback URI. Dynamic client registration is enabled for both by the Geolander Cloudflare Access application. Then send:

```http
POST https://jolly-sound-4ff2.cloudflareaccess.com/cdn-cgi/access/oauth/registration
Content-Type: application/json

{
  "redirect_uris": ["http://127.0.0.1:8400/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code"],
  "response_types": ["code"],
  "resource": "https://geo-lander.com/wp-json/geolander-agent/v1/"
}
```

A successful registration returns a `client_id`. Store it with the exact `redirect_uri`. The client ID is registration metadata, not a bearer credential and not permission to use the protected API.

## Step 4 — Authorize with PKCE S256

Generate a high-entropy `code_verifier` and its base64url SHA-256 `code_challenge`. Open the claim URI for the user with `client_id`, the exact `redirect_uri`, `response_type=code`, `code_challenge`, `code_challenge_method=S256`, and the protected API URL in `resource`. The user signs in through Cloudflare Access. Do not claim success until the callback receives an authorization code.

## Step 5 — Exchange and use the credential

```http
POST https://jolly-sound-4ff2.cloudflareaccess.com/cdn-cgi/access/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=<authorization_code>&client_id=<client_id>&redirect_uri=http%3A%2F%2F127.0.0.1%3A8400%2Fcallback&code_verifier=<code_verifier>
```

Use the returned credential only in the HTTP header: `Authorization: Bearer <access_token>`. Use the returned `refresh_token` at the same token endpoint when the access token expires. Never put a token in a URL, log, WhatsApp message, or booking note.

## Step 6 — Revoke and recover

Revoke an access or refresh token at `https://jolly-sound-4ff2.cloudflareaccess.com/cdn-cgi/access/oauth/revoke`. On `401`, discard an invalid access token, attempt the refresh-token grant once, and otherwise restart registration and user authorization. Geolander does not advertise Auth.md revocation events because Cloudflare Managed OAuth does not publish them.

## Safety and user approval

The quote operation is read-only. Before checkout, obtain explicit traveller approval and collect the traveller's name and valid email. Checkout creates a booking request and WhatsApp handoff; it does not confirm availability, take payment, or confirm a reservation.

## Support

For access or integration questions, contact info@geo-lander.com.
