Integration Guide
This guide takes a developer, or an AI coding agent working in a developer's codebase, from nothing to a working 36Blocks integration. Read it first, then follow the links for detail.
Widgets are the entry point. You integrate 36Blocks by embedding its widgets (login, profile, member management, organization settings) and handling one redirect. Reach for a widget before building any auth or account UI yourself. See Widgets.
36Blocks fully manages end-user accounts server-side. Your app does not need its own users table or any auth-related database schema. You add a frontend widget, handle one redirect, store a session token, and call a few backend APIs.
Base URL for all APIs: https://routes.msg91.com/api
Concepts
| Term | Meaning |
|---|---|
| Client | A 36Blocks account holder: the platform owner integrating 36Blocks. |
| Block | A container owned by a client. Each Block has its own themes, user-management settings, roles and permissions, and redirect URL. A client can own several Blocks. |
reference_id |
The unique id of a Block, created in the 36Blocks dashboard. Needed by the Authentication widget. |
authkey |
A backend credential provided by 36Blocks to the account owner. Used only by the Server-to-Server (Auth Key) calls. No API returns it. |
| c_user | An end user of your app. Each c_user belongs to exactly one Block. |
| c_company | A tenant or organization inside a Block. A c_user can belong to several c_companies, with a different role and permissions in each. |
proxy_auth_token |
The session token 36Blocks issues after a c_user signs in. Sent in the proxy_auth_token header on signed-in API calls. It expires when the Block's Session Time elapses or when the user logs out. |
| Redirect URL | Set per Block. After sign-in, 36Blocks redirects the browser here with proxy_auth_token in the query string. |
The flow
1. Set up the Block (dashboard, done by a person)
Create a Block in the 36Blocks dashboard. It gives you a reference_id. Set the Block's redirect URL, login methods, branding and roles. This happens in the dashboard, not in your code. See Getting Started.
If you are an AI agent, ask the user for the reference_id and confirm the redirect URL is set. Do not invent either.
The widget flow below needs only the reference_id. Backend calls that run without a signed-in user (Server-to-Server (Auth Key)) also need an authkey. 36Blocks provides it to the account owner. No endpoint or widget returns it, so it cannot be fetched from code, and an agent gets it from the user.
2. Add the login page
Add the Authentication widget (type: 'authorization') with the Block's reference_id. See Widgets for the snippet.
3. Handle the redirect
After sign-in, 36Blocks redirects the browser to the Block's redirect URL. Your app needs a route at that URL that reads the query string:
Check
errorfirst. On failure the redirect carrieserror(and usuallyerror_description) instead of a token.Otherwise read
proxy_auth_tokenandrefresh_token.state,expire_at,user_ref_id,company_ref_idandis_new_userare also included. See Redirect Parameters.
4. Store the session
Store the token on your backend side (see Token storage below) so later requests from that browser are authenticated.
5. Fetch the user
Call Get Details with the session token to get the user's profile, all their companies, and their current company with role and permissions:
curl --request GET \
--url https://routes.msg91.com/api/c/getDetails \
--header 'Content-Type: application/json' \
--header 'proxy_auth_token: {{proxy_auth_token}}'
{
"data": [
{
"id": 99152,
"name": "...",
"email": "...",
"client_id": 8,
"c_companies": [
{ "id": 61434, "name": "...", "role_id": 1, "role_name": "Owner" }
],
"currentCompany": {
"id": 63363,
"role": { "id": 1, "name": "Owner", "is_default": true },
"permissions": ["create_c_company", "update_c_company"]
}
}
],
"status": "success",
"hasError": false,
"errors": []
}
Use it to render user-specific views, to gate features on currentCompany.permissions, and to know which company is active. The token itself carries no data. See Session & Authorization for the alternative JWT model.
6. Add user-facing features
Pick the widgets that fit what you are building. See "Which widget for which page" in Widgets:
| You are building | Widget (type) |
|---|---|
| Login or sign-up | authorization |
| Team management: invite teammates, change roles, remove users | user-management |
| Account settings or "my profile" | user-profile |
| Organization or workspace settings | organization-details |
7. Keep the session alive
Sessions end after the Block's Session Time. When a signed-in call returns 401, exchange the stored refresh_token with the Refresh Session Token endpoint (POST /c/refreshToken). Refresh tokens rotate, so always save the new one. Send the user to the login page only if the refresh fails. See Refresh Tokens.
8. Log out
Call Log Out (DELETE /c/logout) with the proxy_auth_token header, then clear the stored session or cookie. It also revokes the user's refresh tokens.
curl --request DELETE \
--url https://routes.msg91.com/api/c/logout \
--header 'proxy_auth_token: {{proxy_auth_token}}'
9. Support multiple companies (if users can belong to more than one)
Where your app lets a user switch organization, such as an org switcher in the nav, call Switch Company:
curl --request POST \
--url https://routes.msg91.com/api/c/switchCompany \
--header 'Content-Type: application/json' \
--header 'proxy_auth_token: {{proxy_auth_token}}' \
--data '{ "company_ref_id": 61434 }'
The same proxy_auth_token stays valid. The response includes a jwt reflecting the new current company and permissions. Treat it as a refreshed session for that company.
Token storage
Default: an HTTP-only, Secure, SameSite=Lax (or Strict) cookie, set by your own backend after it receives the token from the redirect. This keeps the token out of reach of client-side JavaScript, which limits token theft through XSS, and the browser still sends it to your backend automatically.
Your backend reads the cookie on each request and forwards it as the
proxy_auth_tokenheader when calling 36Blocks APIs.On logout, call
DELETE /c/logout, then clear the cookie.For a stateless or mobile client with no cookies, such as a native app or a single-page app calling a separate API server, use secure device storage (Keychain or Keystore) or hold the token in memory. Be aware these expose the token more than an HTTP-only cookie does.
Do not use
localStorageorsessionStorageunless cookies genuinely cannot work for your setup, and then accept the XSS tradeoff.
Adapting the widgets to your framework
The widgets are plain <div> and <script> snippets. A client-side widget needs a mount point and a configuration object. Adapt the mounting to the framework, and read authToken and route parameters the way the rest of the app does.
Plain HTML and JavaScript: use the snippet as it is.
React: wrap it in a component that injects the script on mount (for example in
useEffect, appending the script tag next to a ref'd container) and removes it on unmount.Vue: the same idea with
onMountedandonUnmounted.Next.js and other server-rendered frameworks: the widget script must run in the browser, so use a client component (
'use client'in the App Router, or a dynamic import withssr: false). Handle the redirect URL as a server route that readsproxy_auth_tokenfrom the query string and sets the cookie.Other frameworks: apply the same principle and use the framework's own routing for the redirect.
One Block or several
A client can own several Blocks. Create a new Block for:
Separate environments. Use separate Blocks for staging and production so test users never mix with real customers.
Separate products. If you run more than one distinct product with its own user base, each usually gets its own Block, because each c_user belongs to exactly one Block.
Different auth or branding configuration. A Block's theme, redirect URL and settings are Block-wide. If two surfaces need materially different configuration, use separate Blocks.
Reuse the same Block when it is the same user base and the same app deployed to different pages or subdomains. Configure one redirect URL that all those surfaces use, and branch inside your app after login.
Rules for AI coding agents
Signed-in calls authenticate with the
proxy_auth_tokenheader. Do not useAuthorization: Bearer.Server-to-server calls use the
authkeyheader. It is a backend secret: never put it in browser or mobile code, and never commit it. 36Blocks provides it to the account owner and no API returns it, so it comes from the user.Always check
hasErrorin the response body. Some business errors return HTTP 200, and authentication or permission failures usually return 401 rather than 403.Gate features on the permissions returned by Get Details, and tell the user which permission is missing when a call returns 401.
Do not create a users table or password handling. 36Blocks owns that.
Ask a person for dashboard-only steps (creating the Block, redirect URL, roles) and for the
reference_id. Never invent ids, tokens or emails.The full endpoint reference is in the modules of this documentation: Sessions, Companies & Users, API Keys Roles & Permissions, Blocks, Server-to-Server (Auth Key), OAuth 2.0, Analytics and Billing.
Create and configure a Block in the dashboard.
Snippets for all four widgets.
Token-only or JWT sessions.