Sessions
Companies & Users
API Keys & Permissions
Blocks
Server-to-Server (Auth Key)
OAuth 2.0
Analytics
Billing
Powered by DocStar
  1. API reference
  2. OAuth 2.0
  3. OAuth 2.0 Integration Overview

OAuth 2.0 Integration Overview

36Blocks can act as an OAuth 2.0 authorization server for your Block, letting third-party applications request delegated, scoped access to your users' accounts. It's the same shape as "Connect to GitHub" or "Sign in with Google", but for your own product, under your own control.

You decide which third-party applications are allowed to connect, and exactly what each one can access. Your user is always the one who approves or denies the request, on a consent screen you host yourself, and can revoke that access at any time.

#

What you can build with it

  • Partner and marketplace integrations: let other products connect to a user's account on your platform and read or act on their data, without ever seeing their credentials.

  • Your own first-party apps: a mobile app, CLI, or separate web app that needs to act on behalf of a logged-in user, authenticated the same standards-based way as any external integration.

  • Scoped, revocable access: grant a connecting app only what it actually needs (built-in identity fields, or custom scopes specific to your own product), and cut off access instantly, per connection or per integration.

  • An ecosystem around your product: once this is set up, any developer can build against it using standard OAuth 2.0 (authorization code + PKCE, refresh tokens, a userinfo endpoint) without needing anything custom from you beyond registering their app.

#

The four roles

OAuth role Who this is
Resource Owner Your end user (the person who has an account on your Block).
Authorization Server 36Blocks. We authenticate your user, run the consent screen, and issue the access token.
Resource Server Your own platform or API. A third-party app uses the access token we issue as its credential when calling your APIs.
Client The third-party application requesting access to your user's data.

You control which third-party apps are allowed to request access (by registering each one as an OAuth Config, also called an OAuth client), and which pieces of data they can ask for (via scopes).

#

Key concepts

OAuth Config: one registered third-party integration for your Block. Has a client_id (public identifier) and, for confidential clients, a client_secret. You create and manage these from your Block's dashboard, or with the OAuth Clients endpoints in the Blocks module.

Client type: public or confidential, chosen once when you create the config and not changeable afterward.

  • Confidential clients (a server-side backend that can keep a secret) get a client_secret and authenticate with it.

  • Public clients (a mobile app or single-page app that can't safely hold a secret) have no secret and must use PKCE instead.

PKCE: a proof-of-possession mechanism that protects the authorization code from being intercepted and used by someone other than the app that started the flow. Always required for public clients, optional (but available) for confidential ones. RFC 7636 is the reference.

Scopes: what a connected app is allowed to access. Two are built in:

Scope Grants
profile Name, mobile number, profile picture URL
email Email address

You can also define your own custom scopes (for example tickets:read) for anything specific to your own product. 36Blocks treats these as opaque strings. It's up to your own backend to enforce what a custom scope allows, by checking the token's granted scopes (with the Get OAuth User Info endpoint) before serving the data it's meant to gate.

If a connecting app doesn't send any scopes at all, the flow still completes normally. The app gets no profile or email data and no custom scopes, only a stable user identifier.

#

The flow, end to end

  1. You set up an OAuth Config and (optionally) custom scopes from your Block's dashboard. See Dashboard setup.

  2. You host a consent screen, a page on your own domain where you embed the 36Blocks widget. The third-party app redirects your user's browser there with its OAuth request appended to the URL. See Consent screen. The widget uses the Validate Authorization Request and Submit Authorization Decision endpoints behind the scenes.

  3. Your user logs in (or signs up) and approves or denies the request, using the exact same login UI your users already see today.

  4. The widget redirects the browser back to the third-party app's own redirect_uri, with a one-time authorization code attached (or an error if denied).

  5. The third-party app's backend exchanges that code for an access token and refresh token with the Exchange OAuth Token endpoint (POST /oauth/token).

  6. The third-party app calls Get OAuth User Info (GET /oauth/userinfo) to get the user's identity and confirm exactly which scopes were granted.

  7. The third-party app refreshes the access token as needed, using the same Exchange OAuth Token endpoint with grant_type=refresh_token.

  8. Either your user or you can revoke access at any time. See Revoking access below.

Steps 1 and 2 are things you do once per integration. Steps 3 to 8 happen through the widget and the APIs documented in this module; the third-party app's own developer implements steps 4 to 7 against the endpoint pages.

#

Using the endpoints

  • Token requests come from a backend, never from a browser, and the response is plain JSON without the standard envelope.

  • The access token goes in the proxy_auth_token header, not Authorization and not Bearer-prefixed.

  • Authorization codes are single use. Presenting an already-used code, or an already-rotated-out refresh token, revokes the whole connection, since it is treated as a sign the credential may have leaked. The connecting app must send the user through consent again.

  • Refresh tokens rotate on every use. Each refresh returns a new access_token and a new refresh_token, and the one just used stops working. A refresh token has no expiry timer; it only stops working if the connection is revoked.

  • Errors from the token endpoint are { "error": "invalid_grant", "error_description": "..." } with a 4xx status. invalid_grant is deliberately generic: a wrong secret and a failed PKCE check return the same error.

  • Checking custom scopes: call Get OAuth User Info with the token you were handed and check granted_scopes. If no scopes were granted the response is still a normal 200 with an empty granted_scopes.

#

Revoking access

  • A user revokes their own connection with the Revoke OAuth Grant endpoint (POST /oauth/revoke), called with that user's own proxy_auth_token from a "connected apps" screen on your own site, not by the third-party app. The connection's access token then returns 401 and its refresh token returns invalid_grant.

  • There is no endpoint to list a user's connected apps or grant IDs. If you build a "connected apps" screen, record each grant_id yourself when your backend learns about a new connection.

  • You revoke every connection for an integration at once by disabling its OAuth Config (see Dashboard setup, or the Disable OAuth Client endpoint). Disabling immediately revokes every active connection made through that config.

On this page

  • What you can build with it
  • The four roles
  • Key concepts
  • The flow, end to end
  • Using the endpoints
  • Revoking access
336Blocks User API · API documentation

Build with 36Blocks User. Let AI do the rest.

Copy the instructions, paste them into your AI, and tell it what you want to build.

Paste into your AI and tell it what you want to build.

·
Published with DocStar