Docs/Build an App/Authorization reference

Authorization reference

RocketVerifier Connect follows OAuth 2.0 (RFC 6749) with PKCE (RFC 7636). This page lists every endpoint, parameter and error.

Endpoints

EndpointURLSpec
Issuerhttps://app.rocketverifier.com
Authorizehttps://app.rocketverifier.com/oauth/authorizeRFC 6749 3.1
Tokenhttps://app.rocketverifier.com/api/oauth/tokenRFC 6749 3.2
Revokehttps://app.rocketverifier.com/api/oauth/revokeRFC 7009
Introspecthttps://app.rocketverifier.com/api/oauth/introspectRFC 7662
Dynamic registrationhttps://app.rocketverifier.com/api/oauth/registerRFC 7591
Server metadatahttps://app.rocketverifier.com/.well-known/oauth-authorization-serverRFC 8414
Protected resource metadatahttps://api.rocketverifier.com/.well-known/oauth-protected-resourceRFC 9728
API base URLhttps://api.rocketverifier.com

Identifiers and lifetimes

ValuePrefixLifetimeNotes
Client IDrvapp_PermanentPublic. Safe to ship in a browser or mobile app.
Client secretrv_cs_Until rotatedShown once and stored hashed. Rotate in Dashboard > Developer apps.
Authorization code60 secondsSingle use. A second attempt fails with invalid_grant.
Access tokenrv_at_1 hourSend as Authorization: Bearer. Same header as API keys.
Refresh tokenrv_rt_90 daysRotated on every use. Reusing an old one revokes the grant.

Treat all tokens as opaque strings. Do not parse them; the format after the prefix can change.

GET /oauth/authorize

Redirect the user's browser here. RocketVerifier signs them in, shows the consent screen, then redirects to your redirect_uri.

ParameterRequiredDescription
response_typeYesAlways code.
client_idYesYour app's rvapp_... ID.
redirect_uriYesMust exactly match one of the redirect URIs registered on the app. No wildcards, no prefix matching, and the query string counts.
scopeYesSpace separated list, for example verify:bulk jobs:read account:read. See Scopes.
stateYesAn unguessable value tied to the user's session. Returned unchanged. Check it on the callback.
code_challengePublic clientsBASE64URL(SHA256(code_verifier)), no padding. Recommended for confidential clients too.
code_challenge_methodWith PKCEAlways S256. plain is rejected.
resourceNoRFC 8707 resource indicator, for example https://api.rocketverifier.com. MCP clients send this.
promptNoconsent forces the consent screen even when the user already approved these scopes.

Consent screen

  • The user picks the account to connect: their personal account or an organization where they are owner or admin.
  • Each scope is shown in plain language. The user can set an optional monthly credit cap for your app.
  • Apps that have not passed review show an Unverified app badge.
  • Verified apps skip the screen when the user already granted every requested scope. Unverified apps always show it. Ask for new scopes and the screen lists only what changed.

Success redirect

Redirect
https://yourapp.com/callback?code=CODE_FROM_REDIRECT&state=3f9c2a8e

Error redirect

Redirect
https://yourapp.com/callback?error=access_denied&error_description=The+user+cancelled&state=3f9c2a8e
errorWhen
access_deniedThe user clicked Cancel on the consent screen.
invalid_requestA required parameter is missing or malformed, or PKCE is missing for a public client.
invalid_scopeA scope is unknown or not allowed for this app.
unauthorized_clientThe app is suspended or cannot use this flow.
unsupported_response_typeresponse_type is not code.
server_errorSomething failed on our side. Retry later.

Bad client_id or redirect_uri never redirect

If the client_id is unknown or the redirect_uri does not match, RocketVerifier shows an error page to the user and does not redirect. Redirecting to an unverified URI would leak the code or the error to an attacker.

POST /api/oauth/token

Form-encoded (application/x-www-form-urlencoded). Returns JSON. Never call it from a browser with a client secret.

Client authentication

MethodHowUse for
client_secret_basicHTTP Basic: Authorization: Basic base64(client_id:client_secret)Server apps (recommended)
client_secret_postclient_id and client_secret in the form bodyServer apps that cannot set headers
noneclient_id in the body plus code_verifier (PKCE S256)Public clients: SPA, mobile, desktop, CLI, MCP

grant_type=authorization_code

ParameterRequiredDescription
grant_typeYesauthorization_code
codeYesThe code from the redirect. Single use, valid 60 seconds.
redirect_uriYesThe same value sent to /oauth/authorize.
code_verifierIf PKCE was usedThe original verifier, 43 to 128 characters.
cURL
curl https://app.rocketverifier.com/api/oauth/token \
  -u "rvapp_xxxxxxxxxxxx:rv_cs_xxxxxxxxxxxxxxxx" \
  -d grant_type=authorization_code \
  -d code=CODE_FROM_REDIRECT \
  -d redirect_uri=https://yourapp.com/callback \
  -d code_verifier=VERIFIER

grant_type=refresh_token

ParameterRequiredDescription
grant_typeYesrefresh_token
refresh_tokenYesThe latest rv_rt_... you received.

Success response

200 OK
{
  "access_token": "rv_at_xxxxxxxxxxxxxxxxxxxxxxxx",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "rv_rt_xxxxxxxxxxxxxxxxxxxxxxxx",
  "scope": "verify:bulk jobs:read account:read"
}

scope is what the user approved, which can be fewer scopes than you asked for. Check it before you show features that depend on a scope.

Error response

400 Bad Request
{
  "error": "invalid_grant",
  "error_description": "The refresh token is invalid, expired or revoked"
}
errorStatusMeaning and what to do
invalid_request400Missing or duplicated parameter, or wrong content type. Fix the request.
invalid_client401Unknown client, wrong secret, or no client authentication. Check your credentials or rotated secret.
invalid_grant400Code or refresh token is invalid, expired, already used or revoked; redirect_uri or code_verifier does not match. On refresh: send the user through Connect again.
unauthorized_client400The app is suspended or not allowed to use this grant type.
unsupported_grant_type400Only authorization_code and refresh_token are supported.
invalid_scope400Requested scope is unknown or exceeds what was granted.

Refresh token rotation and reuse detection

  • Every successful refresh returns a new refresh token and invalidates the one you sent.
  • If an already used refresh token is presented again, RocketVerifier assumes it was stolen and revokes the whole grant: every access and refresh token for that user and app stops working. Your app receives a grant.revoked webhook with reason: "refresh_token_reuse".
  • Write the new refresh token to storage before you use the new access token, and run only one refresh at a time per connection. See Security best practices.
  • A refresh token that is not used for 90 days expires. The user has to connect again.

Calling the API

cURL
curl https://api.rocketverifier.com/v1/credits \
  -H "Authorization: Bearer rv_at_xxxxxxxxxxxxxxxxxxxxxxxx"
StatusBody error.codeMeaning
401invalid_tokenAccess token expired, revoked, or the app was suspended. The response carries WWW-Authenticate: Bearer error="invalid_token". Refresh once, then reconnect if refresh fails.
403insufficient_scopeThe token is valid but lacks the scope for this endpoint. Ask the user to reconnect with the extra scope.
402insufficient_creditsThe connected account is out of credits, or your app reached the monthly cap the user set. Tell the user; do not retry.
429rate_limitedThe connected account's rate limit (the organization's for org connections). Honor Retry-After.
401 response
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token"

{
  "error": {
    "code": "invalid_token",
    "message": "The access token is expired or revoked",
    "details": null
  }
}

See Error Codes and Rate Limits for the shared formats.

POST /api/oauth/revoke

RFC 7009. Revoking a refresh token ends the whole grant (the user is disconnected). Revoking an access token ends only that token. Authenticate the same way as the token endpoint. Always returns 200, even for an unknown token.

cURL
curl https://app.rocketverifier.com/api/oauth/revoke \
  -u "rvapp_xxxxxxxxxxxx:rv_cs_xxxxxxxxxxxxxxxx" \
  -d token=rv_rt_xxxxxxxxxxxxxxxxxxxxxxxx \
  -d token_type_hint=refresh_token

POST /api/oauth/introspect

RFC 7662. Your app can introspect only tokens issued to it; anything else returns {"active": false}. Client authentication is required.

cURL
curl https://app.rocketverifier.com/api/oauth/introspect \
  -u "rvapp_xxxxxxxxxxxx:rv_cs_xxxxxxxxxxxxxxxx" \
  -d token=rv_at_xxxxxxxxxxxxxxxxxxxxxxxx
200 OK
{
  "active": true,
  "client_id": "rvapp_xxxxxxxxxxxx",
  "scope": "verify:bulk jobs:read account:read",
  "token_type": "Bearer",
  "exp": 1793534400,
  "iat": 1793530800,
  "iss": "https://app.rocketverifier.com",
  "aud": "https://api.rocketverifier.com"
}

POST /api/oauth/register

RFC 7591 dynamic client registration, for MCP clients and other tools that register themselves. It creates public clients only (token_endpoint_auth_method: none, PKCE required). Redirect URIs must be https or a loopback address (http://127.0.0.1, http://localhost). Apps created this way start unverified. For a confidential server app, create it in the dashboard instead. The full request and response are on the MCP connector page.

Server metadata

Discover every value above from https://app.rocketverifier.com/.well-known/oauth-authorization-server (RFC 8414). Libraries that support discovery need only the issuer.

GET /.well-known/oauth-authorization-server
{
  "issuer": "https://app.rocketverifier.com",
  "authorization_endpoint": "https://app.rocketverifier.com/oauth/authorize",
  "token_endpoint": "https://app.rocketverifier.com/api/oauth/token",
  "revocation_endpoint": "https://app.rocketverifier.com/api/oauth/revoke",
  "introspection_endpoint": "https://app.rocketverifier.com/api/oauth/introspect",
  "registration_endpoint": "https://app.rocketverifier.com/api/oauth/register",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
  "revocation_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
  "introspection_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"],
  "scopes_supported": [
    "verify:single", "verify:bulk", "jobs:read", "jobs:write", "webhooks:manage",
    "credits:read", "monitors:read", "monitors:write", "account:read"
  ],
  "service_documentation": "https://docs.rocketverifier.com/oauth"
}

grant.revoked webhook

Sent to the webhook URL set on your app whenever a connection ends. Delete the stored tokens for that grant and show the Connect button again.

POST to your app's webhook URL
{
  "event": "grant.revoked",
  "event_id": "evt_xxxxxxxxxxxx",
  "timestamp": "2026-11-01T12:00:00Z",
  "data": {
    "grant_id": "4f1d9c2e-...",
    "client_id": "rvapp_xxxxxxxxxxxx",
    "user_email": "jane@acme.com",
    "account_type": "personal",
    "organization_id": null,
    "reason": "user_disconnected"
  }
}
reasonWhen
user_disconnectedThe user clicked Disconnect in Settings > Connected apps.
refresh_token_reuseAn already used refresh token was presented.

Signed with X-RocketVerifier-Signature using your app's webhook secret, the same scheme as every other RocketVerifier webhook. See Verifying Signatures.

More in Build an App