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-serverAuthorization server metadata - GET
/.well-known/oauth-protected-resourceProtected resource metadata - GET
/oauth/authorizeShow the consent screen - POST
/oauth/tokenExchange a grant for a token - POST
/oauth/registerRegister a client dynamically - GET
/oauth/register/{client_id}Read a dynamic registration - POST
/oauth/revokeRevoke a token - GET
/.well-known/oauth-authorization-server/{tail}Authorization server metadata, resource-suffixed - GET
/.well-known/oauth-protected-resource/{tail}Protected resource metadata, resource-suffixed
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"