logo
Development
Search
Core Concepts

Core Concepts

This guide helps developers understand: which extension layer you belong to, which integration mode to take, what's inside the wsa token, and "how far you want to use it."

Two Integration Modes: Push vs. Pull

There are two paths by which the platform hands identity to you. The same wsa contract applies to both; the only difference is "how you obtain the identity authentication information."

Push (Push handoff) — see 03

The user opens your app from within the workspace "Extensions" page, and the platform appends the wsa to your landing page URL and pushes it to you:

https://app.example.com/landing?wsa=<JWT>
                      
                      https://app.example.com/landing?wsa=<JWT>

                    
This code block in the floating window
  • The entry point is inside the workspace.
  • The developer only needs to consume the ?wsa= on the landing page — the simplest approach.
  • Best for: an "embedded app" in the workspace sidebar.

Pull (Pull / M-Auth) — see 04

The developer's extension app places its own "Login with Workspace" button. When the user clicks it, they go to GPTBots to log in ➡️ select a workspace ➡️ and are brought back with the login state. This uses the OAuth2 authorization code + PKCE:

  • The entry point is on the developer's extension app login page.
  • The browser only receives a one-time code; the actual wsa is exchanged by your backend using the code + PKCE and never enters the browser URL.
  • Best for: cases where the developer's extension app is a standalone site that wants to offer "sign in with a GPTBots workspace account."
Push Pull (M-Auth)
Login entry Workspace "Extensions" page Your app's page (login button)
How the token reaches you Pushed directly to the landing page via URL ?wsa= The frontend gets a code, the backend exchanges it for the wsa
Has the browser seen the wsa Yes (must be stripped immediately after landing) Never (more secure)
PKCE required No Yes (S256 enforced)
SDK frontend method consumeHandoff startWorkspaceLogin + completeWorkspaceLogin

Identity Authentication Usage Guide

The platform is only responsible for "passing along the identity"; whether to use it is entirely up to the developer:

Level Meaning What the developer must do
use Verify signature + establish a session + gate features by role consumeHandoff / completeWorkspaceLogin on the frontend, verifyWsa on the backend
receive-only Read the identity for display/analytics but do not create a session or gate anything; keep using your own auth or stay anonymous Only readHandoffToken() (a pure function with no side effects)
ignore Read nothing at all — equivalent to auth_mode=none, just an ordinary external link Nothing

Both verifyWsa and readHandoffToken are pure functions, so "receiving but not using" is zero-cost.

Mapped to the auth_mode chosen at registration:

  • auth_mode = workspace_account: the platform signs the wsa and appends it to the URL (push) / supports M-Auth (pull), and you receive the identity.
  • auth_mode = none: the platform redirects directly, the URL carries no authentication information, and you receive no identity (corresponds to ignore).

The wsa Token Contract (JWT)

The wsa is a JWT signed with HS256 (HMAC-SHA256), valid for 5 minutes (exp = iat + 300).

Standard Claims

Claim Type Description
iss string Fixed value gptbots-workspace, must be verified
aud string The developer extension app host (e.g., app.example.com), parsed from the registered URL, must be verified
sub string The workspace user's accountId, globally unique, usable as the primary user-ID key on the developer side
iat number (seconds) Issued-at time
exp number (seconds) Expiration time, fixed at iat + 300, must be verified

Business Claims

Claim Type Description
role string OWNER / ADMIN / MEMBER — the user's role in this workspace
workspace_id string The workspace ID (i.e., projectId), the multi-tenant isolation key
username string The user's nickname (may be absent)
email string The user's email (may be absent)
avatar string The avatar URL (may be absent)
app_name string The name of the extension app for this particular handoff (useful for auditing, may be absent)

Absent fields: username / email / avatar / app_name will not appear in the payload when the source data is empty, so always handle null values defensively and never assume they are present.

Example payload

{ "iss": "gptbots-workspace", "aud": "app.example.com", "sub": "65f7c8a1d8f3a40012345678", "iat": 1730000000, "exp": 1730000300, "username": "John Doe", "email": "john.doe@example.com", "avatar": "https://cdn.example.com/avatar/u123.png", "role": "ADMIN", "workspace_id": "65a0000000000000000abcde", "app_name": "Contract Review System" }
                      
                      {
  "iss": "gptbots-workspace",
  "aud": "app.example.com",
  "sub": "65f7c8a1d8f3a40012345678",
  "iat": 1730000000,
  "exp": 1730000300,
  "username": "John Doe",
  "email": "john.doe@example.com",
  "avatar": "https://cdn.example.com/avatar/u123.png",
  "role": "ADMIN",
  "workspace_id": "65a0000000000000000abcde",
  "app_name": "Contract Review System"
}

                    
This code block in the floating window

role ≠ the permissions inside your app. The role only reflects the user's role in this workspace; treat it as a "default permission mapping for the first landing," and have your app maintain its own permission model.

Next step: read 03 - Push Handoff or 04 - Pull Login according to the mode you chose; whichever it is, please read 05 - Token Verification and Security.