Quick Start
Get a complete "identity handoff" working end to end with the least amount of code — when a workspace user opens your organization's extension app, their identity information is passed along so your extension app's backend can correctly identify the current user and retrieve their identity details.
- The GitHub repository for the Workspace-Extension-SDK is: https://github.com/GPTBOTS/Workspace-Extension-SDK
- For pull login, see 04 - Pull Login.
The quick tutorial below uses the Push mode for a simple demonstration:
Prerequisite: Obtain the Secret
You first need to obtain the extension app's HS256 signing secret, which is used to complete the organization extension app's identity handoff.
- Have the workspace OWNER/ADMIN go to Workspace → Space Management → Extension Apps and click "Add"
- App name, app icon, App entry URL (
app_home_url) - For the auth mode, choose workspace_account (identity passing required)
- After submitting, the system will display the
App Secretin plaintext one time only — copy and save it immediately. Once the dialog is closed, it can never be viewed again and can only be rotated.
The secret looks like
wext_+ 64 hexadecimal characters (Tier 2). Store it only in your backend (environment variables / a secrets management service) — never put it in the frontend, git, or logs.
Step 1: Backend — The Token Verification Endpoint
Create a backend endpoint that receives the wsa POSTed from the frontend, verifies it with the secret, and, on success, establishes your own session.
// Node / Express example
import express from 'express';
import { verifyWsa, WsaVerificationError } from '@gptbots/workspace-extension-verify';
const app = express();
app.use(express.json());
app.post('/session/exchange', (req, res) => {
try {
const identity = verifyWsa(req.body.wsa, {
secret: process.env.EXTENSION_APP_SECRET, // your secret (backend only)
audience: 'app.example.com', // your app host, must equal the token's aud
});
// identity = { accountId, role, workspaceId, username?, email?, avatar?, appName?, issuedAt?, expiresAt? }
const sid = createYourSession(identity); // replace with your own session
res.cookie('sid', sid, { httpOnly: true, secure: true, sameSite: 'lax' });
res.json(identity);
} catch (e) {
const code = e instanceof WsaVerificationError ? e.code : 'Error';
res.status(401).json({ code }); // reject on any verification failure
}
});
verifyWsaverifies in order: signature →iss→aud→exp(includingiat/nbf) → required claims. Any failure throws aWsaVerificationError. See 06 - SDK API Reference for details.
Step 2: Frontend — Consume the Token on the Landing Page
The user is brought by the platform to your app_home_url?wsa=<JWT>. On this landing page, read the wsa, POST it to your own backend, and then strip it from the URL.
// your landing page
import { consumeHandoff } from '@gptbots/workspace-extension-sdk';
const identity = await consumeHandoff({ exchangeUrl: '/session/exchange' });
// consumeHandoff does the following in sequence:
// 1) reads ?wsa= from the current URL
// 2) POSTs { wsa } to /session/exchange (your backend calls verifyWsa here)
// 3) on success, strips ?wsa= from the URL via history.replaceState
// 4) returns the identity your backend sent back
console.log('current workspace user:', identity.username, identity.role);
if (identity.role === 'MEMBER') hideAdminUI();
Just like that, these two snippets complete a secure identity handoff.
The Full Flow at a Glance
Workspace "Extensions" page GPTBots platform Your app
──────────────── ─────────── ────────
User clicks your app icon ───────────────▶ Verify the clicker is a member of this workspace
Sign a wsa (JWT) valid for 5 minutes with the secret
Open https://app.example.com/?wsa=<JWT> ─────────────────────────────▶ Landing page
consumeHandoff()
◀── POST /session/exchange { wsa } ──
Your backend verifyWsa() → identity
Establish your own session
Strip ?wsa= from the URL
Local Debugging Tips
- The
wsais valid for only 5 minutes and is a one-time bootstrap token — after exchanging it for your own session, do not includewsain subsequent requests. audiencemust exactly equal the host you registered (app.example.com); port/protocol are not part of theaud, but the host must match, otherwise you getWrongAudience.- On a verification failure, first check
WsaVerificationError.code(InvalidSignature/Expired/WrongAudience…) and cross-reference 07 - Troubleshooting. - Want to just read the identity for display without creating a session? Replace
consumeHandoffwithreadHandoffToken()(see 02 - The Three Consumption Levels).
Next step: read 02 - Core Concepts to understand the token contract and the two modes, or go straight to 03 - Push Handoff / 04 - Pull Login for the full details.
Integrate your own web system into the GPTBots workspace as an "extension app." When a workspace user opens your app from Workspace → Extensions, GPTBots securely hands off the user's workspace identity to you as a short-lived signed token (wsa, a JWT). Your app uses this to identify the user without a separate login and unlock features by role.
Table of Contents
| File | Audience | Contents |
|---|---|---|
| Quick Start.md | Everyone | Get a complete identity handoff working in 10 minutes (with minimal usable frontend + backend code) |
| Core Concepts.md | Everyone | The two extension-app layers, the two integration modes, auth_mode, the three consumption levels, and the wsa token contract |
| Push Handoff.md | Push integrators | User opens the app on the extensions page → the platform pushes the wsa to you (the ?wsa= landing page) |
| Pull Login.md | Pull integrators | Your app places a "Login with GPTBots Workspace" button (OAuth2 authorization code + PKCE) |
| Token Verification and Security.md | Everyone (required reading) | The mandatory verification checklist, secret custody, and multi-language verification without the SDK (Java / Node / Python) |
| SDK API Reference.md | Everyone | The complete API, types, and error codes for the two SDK packages |
| Troubleshooting.md | Everyone | FAQ, the master error-code table, and common pitfalls |
SDK Overview
The official SDK is framework-agnostic with zero runtime dependencies and consists of two packages (both inside the archive workspace-extension-sdk-0.1.0.zip):
| Package | Runs in | Purpose |
|---|---|---|
@gptbots/workspace-extension-verify |
Your backend (Node) | Verify wsa with the secret → get a WorkspaceIdentity; exchange code → wsa on the backend |
@gptbots/workspace-extension-sdk |
Browser | Read / strip / exchange the wsa; initiate "Login with GPTBots Workspace" |
You don't have to use the SDK — the
wsais a standard HS256 JWT, and any language's JWT library can verify it. See 05 - Token Verification and Security.
Installing Locally from the Archive
# After extracting, both packages ship with a prebuilt dist and can be used as local dependencies directly:
unzip workspace-extension-sdk-0.1.0.zip
npm i ./workspace-extension-sdk/packages/verify # backend
npm i ./workspace-extension-sdk/packages/browser # frontend
Once the SDK is published to npm, you can simply run
npm i @gptbots/workspace-extension-verify/npm i @gptbots/workspace-extension-sdk.
Pre-Integration Alignment Checklist
- Confirmed you have already created the organization extension app and obtained its secret
- Decided on the integration mode: Push or Pull (M-Auth)
- The
app_home_url(push) / the host ofredirect_uri(pull) exactly matches the registered information - The backend has implemented
wsaverification: signature +iss+aud+exp— all four are mandatory - On landing, immediately
history.replaceStateto stripwsa/codefrom the URL - Exchanged the token for the app's own session; subsequent requests no longer pass through the
wsa - The app server's clock is NTP-synced
