OAuth API

The OAuth 2.1 authorization server that third-party applications integrate against. The protocol endpoints live on the API root, unversioned, because the RFCs are their contract and the metadata document advertises them there.

Updated

On this page

9 operations, generated from openapi/signclad.v1.yaml. Try them in the interactive reference, browse every endpoint group, or read the guides for the prose version.

GET /.well-known/oauth-authorization-server

Authorization server metadata Extension

RFC 8414 discovery. Everything a client needs to talk to the authorization server without hard-coding a URL. Cached for five minutes. The same document is served from any path suffix (/.well-known/oauth-authorization-server/anything), because clients differ on where they look.

Base URL
https://api.signclad.com
Authentication
None — this operation is public

Responses

Status Description
200 The metadata document.

Example request

curl -X GET https://api.signclad.com/.well-known/oauth-authorization-server \
  -H "X-Api-Key: $SIGNCLAD_API_KEY"

GET /.well-known/oauth-protected-resource

Protected resource metadata Extension

RFC 9728 discovery: which authorization server protects this API, which scopes it understands, and how long a resource server may cache an introspection result.

Base URL
https://api.signclad.com
Authentication
None — this operation is public

Responses

Status Description
200 The metadata document.

Example request

curl -X GET https://api.signclad.com/.well-known/oauth-protected-resource \
  -H "X-Api-Key: $SIGNCLAD_API_KEY"

GET /oauth/authorize

Show the consent screen Extension

The authorization endpoint. PKCE is mandatory: code_challenge with code_challenge_method=S256, no exceptions and no default. response_type must be code; there is no implicit grant. The screen is skipped when there is nothing to decide. A grant that already covers this client, this audience, and every requested scope is honoured silently and the browser goes straight back with a code — showing a consent screen for something already approved only teaches people to click through consent screens. Three things force it anyway: prompt=consent, a request for a scope the existing grant does not carry, and a grant whose workspace the person has since left. Otherwise, three possible answers. No session redirects to the login page with a redirect back here. A browser gets the consent page as HTML. Accept: application/json gets the same information as JSON, for a SPA rendering its own consent screen. Failures split by whether the redirect URI can be trusted yet. An unknown client, or a redirect_uri that does not exactly match a registered one, is answered here — never redirected, because redirecting would make this an open redirector. Everything after that (bad scope, bad PKCE, bad resource) redirects to the client with error, error_description, the state if there was one, and always iss.

Base URL
https://api.signclad.com
Authentication
None — this operation is public

Query parameters

Name Type Required Description
client_id string Required
redirect_uri string (uri) Optional Required unless the client registered exactly one. Matched exactly, except that the port is ignored for loopback addresses so a native app can bind any free port.
response_type string Required
code_challenge string Required 43 characters of unreserved base64url.
code_challenge_method string Required
scope string Optional Space-delimited. Empty means every scope the client registered.
state string Optional
nonce string Optional
resource string (uri) Optional RFC 8707 audience. One absolute http/https URI, no fragment. Defaults to this API.
prompt string Optional A space-delimited list (OpenID Connect Core §3.1.2.1), the same production scope uses. It was compared as a single string until the error-envelope pass, which meant prompt=consent login silently skipped the very screen the client had insisted on.…

Responses

Status Description
200 The consent screen, as HTML for a browser or JSON for a SPA.
302 To the login page when there is no session; straight back to the client with a code when an existing grant covers the request; or back to the client with an error when the failure happens after th…
400 The OAuth error envelope: error plus a human-readable error_description. Always Cache-Control: no-store.
401 Client authentication failed.
403 The OAuth error envelope: error plus a human-readable error_description. Always Cache-Control: no-store.
429 Rate limited. The message contains the literal 429 Too Many Requests for compatibility with clients that match on it.…

Example request

curl -X GET https://api.signclad.com/oauth/authorize \
  -H "X-Api-Key: $SIGNCLAD_API_KEY"

POST /oauth/token

Exchange a grant for a token Extension

Three grants: authorization_code, refresh_token, and client_credentials. Confidential clients authenticate with HTTP Basic or with client_id and client_secret in the body; public clients send client_id alone and are refused if they present a secret. Refresh tokens rotate and detect reuse. Using one twice revokes the whole family and forces a fresh authorization — the reply says so. A refresh may narrow scope, never widen it, and can never change the token's audience. refresh_token is present only when offline_access was granted, and never on client_credentials. nonce comes back only when the code carried one.

Base URL
https://api.signclad.com
Authentication
None — this operation is public

Request body

application/x-www-form-urlencoded

Property Type Required Description
grant_type string Required
client_id string Optional
client_secret string Optional
code string Optional
code_verifier string Optional
redirect_uri string (uri) Optional Required unless the client registered exactly one. Must match the code's.
refresh_token string Optional
resource string (uri) Optional Must match the audience the grant was issued for; a refresh cannot change it.
scope string Optional On a refresh, may only narrow. On client credentials, defaults to the client's scopes.

Responses

Status Description
200 The token.
400 The OAuth error envelope: error plus a human-readable error_description. Always Cache-Control: no-store.
401 Client authentication failed.
429 Rate limited. The message contains the literal 429 Too Many Requests for compatibility with clients that match on it.…

Example request

curl -X POST https://api.signclad.com/oauth/token \
  -H "X-Api-Key: $SIGNCLAD_API_KEY"

Example response (200)

{
  "access_token": "sca_9f8e7d6c5b4a39281706f5e4d3c2b1a0",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "documents:read documents:write offline_access",
  "refresh_token": "scr_1a2b3c4d5e6f708192a3b4c5d6e7f809"
}

POST /oauth/register

Register a client dynamically Extension

RFC 7591 dynamic registration, unauthenticated, so an assistant can connect without anybody pasting a client id. It issues public clients only: token_endpoint_auth_method must be none, and a confidential client for server-to-server work is created in the app instead. Redirect URIs must be HTTPS, a loopback address, or a reverse-domain private-use scheme. The response carries a registration_access_token and registration_client_uri — the only time the token is shown.

Base URL
https://api.signclad.com
Authentication
None — this operation is public

Request body

application/json

Property Type Required Description
redirect_uris array of string Required HTTPS with a host, a loopback address (127.0.0.1, ::1, localhost), or a reverse-domain private-use scheme such as com.example.app:/callback. No fragments.
client_name string Optional
client_uri string Optional
contacts array of string Optional
grant_types array of string Optional
logo_uri string Optional
policy_uri string Optional
response_types array of string Optional
scope string Optional Space-delimited.
software_id string Optional
software_statement string Optional Stored as sent. Not verified.
software_version string Optional
token_endpoint_auth_method string Optional Dynamic registration issues public clients only.
tos_uri string Optional

Responses

Status Description
201 The registered client.
400 The OAuth error envelope: error plus a human-readable error_description. Always Cache-Control: no-store.
403 The OAuth error envelope: error plus a human-readable error_description. Always Cache-Control: no-store.
429 Rate limited. The message contains the literal 429 Too Many Requests for compatibility with clients that match on it.…

Example request

curl -X POST https://api.signclad.com/oauth/register \
  -H "X-Api-Key: $SIGNCLAD_API_KEY"

GET /oauth/register/{client_id}

Read a dynamic registration Extension

RFC 7592. Authenticated with the registration_access_token as a bearer token. Returns the same document as the registration minus the token and the management URI. A client that was not dynamically registered is a 404.

Base URL
https://api.signclad.com
Authentication
Registration access token

Path parameters

Name Type Description
client_id string

Responses

Status Description
200 The registration.
401 The OAuth error envelope: error plus a human-readable error_description. Always Cache-Control: no-store.
404 The OAuth error envelope: error plus a human-readable error_description. Always Cache-Control: no-store.
429 Rate limited. The message contains the literal 429 Too Many Requests for compatibility with clients that match on it.…

Example request

curl -X GET https://api.signclad.com/oauth/register/{client_id} \
  -H "X-Api-Key: $SIGNCLAD_API_KEY"

POST /oauth/revoke

Revoke a token Extension

RFC 7009. Answers 200 with a JSON null body whether the token existed, was already revoked, belonged to another client, or was never ours — a revocation endpoint that distinguished those would be a token oracle. token_type_hint is accepted and ignored.

Base URL
https://api.signclad.com
Authentication
None — this operation is public

Request body

application/x-www-form-urlencoded

Property Type Required Description
token string Required
client_id string Optional
client_secret string Optional
token_type_hint string Optional Accepted and ignored.

Responses

Status Description
200 Revoked, or there was nothing to revoke. The body is the literal null.
400 The OAuth error envelope: error plus a human-readable error_description. Always Cache-Control: no-store.
401 Client authentication failed.
429 Rate limited. The message contains the literal 429 Too Many Requests for compatibility with clients that match on it.…

Example request

curl -X POST https://api.signclad.com/oauth/revoke \
  -H "X-Api-Key: $SIGNCLAD_API_KEY"

GET /.well-known/oauth-authorization-server/{tail}

Authorization server metadata, resource-suffixed

The same document as /.well-known/oauth-authorization-server, served at the path-suffixed form RFC 8414 §3.1 describes for an issuer with a path component. Clients differ on which of the two they try first, so Signclad answers both identically rather than making the choice matter.

Base URL
https://api.signclad.com
Authentication
None — this operation is public

Path parameters

Name Type Description
tail string Whatever follows the well-known prefix. RFC 8414 §3.1 inserts the issuer's path component here; Signclad's issuer has none, so the segment is ignored and the same document is served whatever it holds.

Responses

Status Description
200 The metadata document.

Example request

curl -X GET https://api.signclad.com/.well-known/oauth-authorization-server/{tail} \
  -H "X-Api-Key: $SIGNCLAD_API_KEY"

GET /.well-known/oauth-protected-resource/{tail}

Protected resource metadata, resource-suffixed

The same document as /.well-known/oauth-protected-resource, served at the path-suffixed form RFC 9728 describes. The WWW-Authenticate header on a 401 points at the bare path; both answer identically.

Base URL
https://api.signclad.com
Authentication
None — this operation is public

Path parameters

Name Type Description
tail string Whatever follows the well-known prefix. RFC 8414 §3.1 inserts the issuer's path component here; Signclad's issuer has none, so the segment is ignored and the same document is served whatever it holds.

Responses

Status Description
200 The metadata document.

Example request

curl -X GET https://api.signclad.com/.well-known/oauth-protected-resource/{tail} \
  -H "X-Api-Key: $SIGNCLAD_API_KEY"