Reference

OAuth

Sign in with Tabbio: the authorization code flow with PKCE, plus token refresh, revocation and introspection.

Authorization server metadata

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

No authenticationNo scope required

The RFC 8414 discovery document. Standard OAuth clients read this to find the authorize, token, revocation and introspection endpoints, so you rarely need to hardcode them. Returned as plain JSON, not the API envelope.

Response

FieldType
issueralwaysstring
authorization_endpointalwaysstring
token_endpointalwaysstring
revocation_endpointalwaysstring
introspection_endpointalwaysstring
userinfo_endpointalwaysstring
scopes_supportedalwaysstring[]
response_types_supportedalwaysstring[]
grant_types_supportedalwaysstring[]
code_challenge_methods_supportedalwaysstring[]
token_endpoint_auth_methods_supportedalwaysstring[]
service_documentationalwaysstring

Status codes

  • 200

    The metadata document.

Request
curl https://server.tabbio.com/.well-known/oauth-authorization-server
Response 200
{
  "issuer": "<issuer>",
  "authorization_endpoint": "<authorization_endpoint>",
  "token_endpoint": "<token_endpoint>",
  "revocation_endpoint": "<revocation_endpoint>",
  "introspection_endpoint": "<introspection_endpoint>",
  "userinfo_endpoint": "<userinfo_endpoint>",
  "scopes_supported": [
    "<scopes_supported>"
  ],
  "response_types_supported": [
    "<response_types_supported>"
  ],
  "grant_types_supported": [
    "<grant_types_supported>"
  ],
  "code_challenge_methods_supported": [
    "<code_challenge_methods_supported>"
  ],
  "token_endpoint_auth_methods_supported": [
    "<token_endpoint_auth_methods_supported>"
  ],
  "service_documentation": "<service_documentation>"
}

Start the authorization flow

GET/oauth/authorize

No authenticationNo scope required

Send the user’s browser here to begin "Sign in with Tabbio". The endpoint redirects to the Tabbio consent screen with every parameter intact; the user signs in if needed, chooses which CV to share and what to include, and is sent back to your redirect_uri with code and state. PKCE is required for every client, public and confidential.

Query parameters

FieldTypeDescription
response_typerequiredstring

Always code.

One of code

client_idrequiredstring

Your app’s client id (tbo_ci_...).

redirect_urirequiredstring

One of the redirect URIs registered for the app, matched exactly.

scoperequiredstring

Space separated list of: profile, email, cv:read, cv:contact.

statestring

Opaque value echoed back verbatim. Use it to defeat CSRF.

code_challengerequiredstring

BASE64URL(SHA256(code_verifier)). PKCE is required for every client.

code_challenge_methodrequiredstring

Always S256. plain is rejected.

One of S256

Status codes

  • 302

    Redirect to the Tabbio consent screen.

Request
curl "https://server.tabbio.com/oauth/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&scope=$SCOPE&code_challenge=$CODE_CHALLENGE&code_challenge_method=S256"

Introspect a token

POST/oauth/introspect

No authenticationNo scope required

RFC 7662. Only the app that owns the token learns anything about it; every other case answers { "active": false }. Like the token endpoint, this answers the flat RFC body rather than the API envelope, with active at the top level and Cache-Control: no-store, and reports errors in the RFC 6749 { error, error_description } shape.

Request body

Sent as application/x-www-form-urlencoded.

FieldTypeDescription
tokenrequiredstring

The access or refresh token to act on.

token_type_hintstring
client_idstring
client_secretstring

Response

FieldTypeDescription
activealwaysboolean
scopestring
client_idstring
token_typestring

One of Bearer

substring

The Tabbio user id.

expinteger or null

Expiry as a Unix timestamp.

connection_idstring

Status codes

  • 200

    The token state, as the flat RFC 7662 body.

  • 400

    The request was malformed.

  • 401

    Client authentication failed.

Request
curl -X POST https://server.tabbio.com/oauth/introspect \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d 'token=tbo_at_9QpX2fR8kLm4TnQ7vWxZ1bC'

A live token this app owns.

Response 200
{
  "active": true,
  "scope": "profile email cv:read cv:contact",
  "client_id": "tbo_ci_2Kd81aQ7vXpL9mNr3TzW",
  "token_type": "Bearer",
  "sub": "usr_2f8a91",
  "exp": 1788000000,
  "connection_id": "con_9d21f4"
}

Revoke a token

POST/oauth/revoke

No authenticationNo scope required

RFC 7009. Revoking a refresh token also revokes its rotation family, the connection’s live access tokens and its durable CV links, so a partner ending the session keeps no bearer PDF URL; revoking an access token revokes only that token. Always answers success, even for a token that was already unknown. RFC 7009 specifies no success body and tells clients to ignore whatever arrives with the 200, so this endpoint keeps the standard Tabbio { data, error, meta } envelope, unlike the token and introspection endpoints, which answer the flat OAuth bodies their RFCs define.

Request body

Sent as application/x-www-form-urlencoded.

FieldTypeDescription
tokenrequiredstring

The access or refresh token to act on.

token_type_hintstring
client_idstring
client_secretstring

Response

These fields sit inside data.

FieldTypeDescription
revokedalwaysboolean

One of

Status codes

  • 200

    The token is no longer usable. The body is the API envelope; RFC 7009 clients may ignore it.

  • 400

    The request was malformed.

  • 401

    Client authentication failed.

Request
curl -X POST https://server.tabbio.com/oauth/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d 'token=tbo_rt_4Kd81aQ7vXpL9mNr3TzWyB6'
Response 200
{
  "data": {
    "revoked": true
  },
  "error": null,
  "meta": null
}

Exchange a code or refresh a token

POST/oauth/token

No authenticationNo scope required

The RFC 6749 token endpoint. Authenticate with HTTP Basic (client_id:client_secret) or with the credentials in the body; a public client sends client_id alone. Refresh tokens rotate on every use: the old one is revoked, and presenting it again revokes the whole family, so store the new one before you drop the old one. This endpoint answers the flat OAuth body, not the API envelope.

Request body

Sent as application/x-www-form-urlencoded.

FieldTypeDescription
grant_typerequiredstring

authorization_code or refresh_token.

One of authorization_code, refresh_token

codestring

The authorization code, for authorization_code.

redirect_uristring

The redirect URI from the authorization request. Must match exactly.

code_verifierstring

The PKCE verifier whose challenge was sent to the authorize endpoint.

refresh_tokenstring

The refresh token, for refresh_token.

scopestring

Optional on refresh, and may only narrow the granted scope.

client_idstring

Required unless the client authenticates with HTTP Basic.

client_secretstring

Confidential clients only. Prefer HTTP Basic.

Response

FieldTypeDescription
access_tokenalwaysstring
token_typealwaysstring

One of Bearer

expires_inalwaysinteger

Seconds until the access token expires.

refresh_tokenalwaysstring
scopealwaysstring

The scopes actually granted, space separated.

Status codes

  • 200

    A new access and refresh token pair.

  • 400

    The grant was refused.

  • 401

    Client authentication failed.

Request
curl -X POST https://server.tabbio.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d 'grant_type=authorization_code&code=tbo_ac_yLh0dJ8Q1s5B&redirect_uri=https%3A%2F%2Fpartner.example%2Fcallback&code_verifier=M25iVXpKU3puUjFaYWg3T1NDTDQtcW1ROUY5YXlwalNoc0hhakxifmZH'
Response 200
{
  "access_token": "tbo_at_9QpX2f",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "tbo_rt_4Kd81a",
  "scope": "profile email cv:read"
}

Base URL https://server.tabbio.com. Every response outside the token endpoint uses the { data, error, meta } envelope.