Skip to content

OAuth flows

Use OAuth flows to sign a person or an agent in to Port OS and get an access token for the other APIs.

Port OS requires authorization for calls against its APIs. It uses OAuth to issue the tokens that authorize those calls, and it supports extensions that let agents connect automatically: Dynamic Client Registration, client information metadata documents, PKCE and others.

This section covers discovery metadata, client registration, authorize and consent, and the callback that returns the authorization code. Registration alone grants no access to resources. Operation scopes restrict delegated authority in addition to the permission rules for principals and resources.

Discover OAuth and DCR endpoints

View source specification ↗
GET /.well-known/oauth-authorization-server

Discover the canonical issuer and endpoints for the deployed environment. Public REST grants use issuer as resource; MCP grants use issuer/mcp. CIMD client IDs must be public HTTPS metadata URLs. Registration is anonymous; device access requires user consent.

Required scope

Not required

Returns

200

Authorization server metadata.

Fields
issuerstringRequired

format: "uri"

authorization_endpointstringRequired

format: "uri"

token_endpointstringRequired

format: "uri"

registration_endpointstring

Advertised when new anonymous registration is enabled; omitted when disabled.

format: "uri"

revocation_endpointstringRequired

format: "uri"

jwks_uristring

format: "uri"

scopes_supportedarray<string>Required
code_challenge_methods_supportedarray<string>
Itemstring

Allowed values

  • S256
token_endpoint_auth_methods_supportedarray<string>
client_id_metadata_document_supportedboolean
authorization_response_iss_parameter_supportedboolean

JSON Web Key Set

View source specification ↗
GET /.well-known/jwks.json

Returns the JSON Web Key Set (JWKS) containing the public keys used to verify JWT signatures. This endpoint is publicly accessible and does not require authentication. Responses are cached for one hour.

Required scope

Not required

Returns

200

JWKS retrieved successfully

Fields
keysarray<JsonWebKey>
ktystring

Key type

algstring

Algorithm

kidstring

Key ID

usestring

Public key use

nstring

RSA modulus (Base64url encoded)

estring

RSA exponent (Base64url encoded)

OAuth protected resource metadata

View source specification ↗
GET /.well-known/oauth-protected-resource

Returns OAuth 2.0 Protected Resource Metadata as defined by RFC 9728. This endpoint is publicly accessible and does not require authentication. Responses are cached for one hour.

Required scope

Not required

Returns

200

Protected resource metadata retrieved successfully

Fields
resourcestring

The protected resource identifier

authorization_serversarray<string>

Authorization servers that can issue tokens for this resource

scopes_supportedarray<string>

Scopes supported by this resource

bearer_methods_supportedarray<string>

Methods supported for presenting bearer tokens

MCP OAuth protected resource metadata

View source specification ↗
GET /.well-known/oauth-protected-resource/mcp

Returns OAuth 2.0 Protected Resource Metadata for the MCP endpoint as defined by RFC 9728. This endpoint is publicly accessible and does not require authentication. Responses are cached for one hour.

Required scope

Not required

Returns

200

MCP protected resource metadata retrieved successfully

Fields
resourcestring

The protected resource identifier

authorization_serversarray<string>

Authorization servers that can issue tokens for this resource

scopes_supportedarray<string>

Scopes supported by this resource

bearer_methods_supportedarray<string>

Methods supported for presenting bearer tokens

OAuth2 Device Authorization

View source specification ↗
POST /auth/device-authorization

This API is used by your device to obtain authorization from the resource owner via a device code or QR code that your device can scan.

See the OAuth device authorization docs for more.

Uses the existing managed-client device flow. This endpoint is public, but validates its client and supported device grant; anonymous DCR clients support authorization_code and optional refresh_token, and cannot start the device flow.

Required scope

Not required

Request body

Required

Fields

client_idstringRequired

The OAuth client identifier

scopestring

Space-separated list of scopes requested by the client

Returns

200

Device authorization initiated successfully

Fields
device_codestringRequired

The device verification code used to poll the token endpoint

user_codestringRequired

The user verification code displayed to the user

verification_uristringRequired

The URI where the user should enter the user code

verification_uri_completestring

The complete URI including the user code (optional, for convenience)

expires_inintegerRequired

The lifetime in seconds of the device_code and user_code

intervalintegerRequired

The minimum amount of time in seconds that the client should wait between polling requests

Errors

400

Invalid request parameters

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Register a public OAuth client

View source specification ↗
POST /oauth/register

RFC 7591 anonymous public-client registration. No Google session is required. This registration gives no user or resource permissions. Public clients must use PKCE S256, resource-bound authorization_code flow and explicit user consent. Client name, software_id and client_uri are unverified claims, not proof of Muse or any other product. Untrusted software_statement is rejected. Remote callbacks require HTTPS. HTTP is allowed for localhost or literal loopback IPs only, and local callbacks cannot be mixed with remote callbacks. SHA-256 of canonical client_name, sorted redirect_uris, sorted grant_types, sorted response_types and token_endpoint_auth_method identifies a registration. A repeated fingerprint returns the original client_id and accepted metadata, including its original scopes; it never overwrites metadata or expands scopes. Reused registrations do not consume new-registration quota. Unknown metadata extensions are ignored as required by RFC 7591. The deployment enforces rolling registration and retained-client quotas.

Required scope

Not required

Request body

Required

Fields

client_namestring

Unverified display name.

maxLength: 200

redirect_urisarray<string>Required

Exact callbacks must form either an entirely localhost/loopback set or an entirely remote HTTPS set. HTTP is allowed only for localhost or literal loopback IPs. Local and remote callbacks cannot be mixed; user information and fragments are forbidden.

Itemstring

format: "uri"

maxLength: 2048

token_endpoint_auth_methodstringRequired

Allowed values

  • none
grant_typesarray<string>

authorization_code, optionally with refresh_token, each at most once. Omitted, the server registers authorization_code and refresh_token and returns them.

uniqueItems: true

Itemstring

Allowed values

  • authorization_code
  • refresh_token
response_typesarray<string>
Itemstring

Allowed values

  • code
scopestring

Space-separated OAuthScope values accepted by the deployment DCR allowed_scopes policy. Omission selects every DCR-allowed scope; the user's consent at authorization still decides what a token gets.

client_uristring

Unverified descriptive URL; never fetched as evidence.

maxLength: 2048

software_idstring

Unverified software claim.

maxLength: 200

software_versionstring

maxLength: 100

software_statementstring

Unsupported; rejected if supplied.

Returns

201

Public client created; no client_secret is issued.

Fields
(payload)any

Errors

400

Invalid metadata, redirect URI, or unapproved software statement.

Check the request fields and any validation details, then correct the payload.

415

Use application/json.

Inspect the returned code and family and follow the error handling guide.

429

Registration quota reached. Wait before retrying; do not loop.

Wait for Retry-After or details.retryAfterSeconds when supplied; otherwise use backoff.

Response headers
Retry-After
See the source specification for this header.
503

Registration storage unavailable.

Wait for the provider or bridge to recover, then retry safely with backoff.

Open user consent for a resource-bound public client

View source specification ↗
GET /oauth/authorize

Browser entry for registered DCR or CIMD clients. Redirects to the sign-in and consent UI. The client must start its registered callback listener first, generate random state and an S256 challenge, and wait for the user. Validate callback state and iss before exchanging the code. A CIMD client_id is an HTTPS, non-loopback URL of a metadata document that the server fetches (size-limited). The document must repeat the URL as client_id, name the client, list HTTPS redirect_uris that pass the server's redirect rules, and declare either public authentication (none) or private_key_jwt with an RS256 or ES256 signing algorithm and an HTTPS jwks_uri. The redirect_uri you send must be one of the listed redirect_uris. Any other metadata is rejected with invalid_client. There is no per-deployment allowlist of CIMD client URLs.

Required scope

Not required

Query parameters

client_idstringRequired

The client_id of the requested resource.

redirect_uristringRequired

The redirect_uri of the requested resource.

format: "uri"

response_typestringRequired

The response_type of the requested resource.

Allowed values

  • code
scopestringRequired

The scope of the requested resource.

statestringRequired

The state of the requested resource.

resourcestring

Canonical issuer for REST or issuer/mcp for MCP. Omission defaults to REST.

format: "uri"

code_challengestringRequired

The code_challenge of the requested resource.

code_challenge_methodstringRequired

The code_challenge_method of the requested resource.

Allowed values

  • S256

Returns

302

Navigate to sign-in and pending consent.

No response body.

Response headers
Locationstring

format: "uri"

Errors

400

Invalid or unsupported OAuth request.

Check the request fields and any validation details, then correct the payload.

Complete pending consent with a signed user session

View source specification ↗
POST /oauth/authorize

The website uses this endpoint after sign-in. Agents open the authorization URL and wait for the user; they never manufacture the user session.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Required

Fields

request_idstringRequired
approvedbooleanRequired
scopestring

Returns

200

One-time browser continuation URL. Navigate the browser to receive a 302 to the registered callback.

Fields
redirect_urlstringRequired

format: "uri"

Errors

400

Invalid, expired or consumed request.

Check the request fields and any validation details, then correct the payload.

401

User sign-in required.

Obtain a valid access token, then retry.

Read a pending request for the signed-in consent page

View source specification ↗
GET /oauth/authorization-request

Returns server-stored consent details to the authenticated website. Descriptive client metadata is unverified. Agents use the public authorization endpoint and wait for the user; a delegated device token cannot read this session-only endpoint.

Required scope

Any authenticated access token

Query parameters

request_idstringRequired

The request_id of the requested resource.

Returns

200

Pending consent details. Response is not cacheable.

Fields
client_idstringRequired
client_namestringRequired
redirect_uristringRequired

format: "uri"

resourcestringRequired

format: "uri"

scopesarray<string>Required

Errors

400

Invalid, expired or consumed request.

Check the request fields and any validation details, then correct the payload.

401

User sign-in required.

Obtain a valid access token, then retry.

Read the application name before signing in

View source specification ↗
GET /oauth/authorization-request/client

Returns only the registration display identity from an unexpired, unused pending authorization request. The request is not consumed. No account, callback, scopes, state, PKCE or authorization response data is exposed. Client names are unverified registration claims. Full consent details and approval still require account sign-in.

Required scope

Not required

Query parameters

request_idstringRequired

Opaque pending authorization request identifier from the browser handoff.

Returns

200

Application display identity. The response is not cacheable.

Fields
client_idstringRequired

The registered OAuth client identifier.

client_namestringRequired

Display name captured from the client registration, including CIMD metadata.

Errors

400

Invalid, expired or consumed authorization request.

Check the request fields and any validation details, then correct the payload.

Redirect the browser to the approved OAuth callback

View source specification ↗
GET /oauth/authorization-response

Navigate the browser here using the continuation returned by authenticated consent. The opaque reference expires after two minutes and is consumed once. The server chooses the stored callback; caller-supplied redirect destinations are never used. Approval carries code, original state and issuer; denial carries access_denied, original state and issuer. No bearer token is needed.

Required scope

Not required

Query parameters

request_idstringRequired

Opaque, single-use continuation reference returned by authenticated consent.

Returns

302

Navigate with GET to the exact registered callback.

No response body.

Response headers
Locationstring

format: "uri"

Response headers
Cache-Controlstring

no-store

Response headers
Referrer-Policystring

no-referrer

Errors

400

Missing, wrong-stage, expired or consumed continuation reference.

Check the request fields and any validation details, then correct the payload.