Outcome
Create an application-scoped surface credential from a current human sign-in, with no context switch, new entitlement or change to workspace grants.
Before you start
-
Verify the human identity and intended pinned credential context, then discover the canonical application. The fixture identities and signing output below are synthetic and unusable.
-
Keep account eligibility, surface/workspace availability and operation-specific permission or conversation consent separate. A result here never widens authority.
Discover the application
topolo whoami --json
topolo apps --json
topolo actions get app_topolo_auth.surface_sessions.create --detail --json
Input fields
| Field | Required | Meaning |
|---|---|---|
app_id | Yes | Registered application to scope the surface to. Does not select an account or organisation. |
Interpret the response
Supply only app_id; creation does not switch context, select another account, assign seats, restore membership or grant work access. A current human source is required. API keys, delegated actor headers and service principals cannot substitute for that identity. A surface credential cannot mint another surface credential.
data.access_token is sensitive, token_type is Bearer and expires_in is at most 300 seconds. A context-RBAC or refresh source with less remaining lifetime produces a shorter TTL. The synthetic signing result in local examples is unusable; it is not a live credential.
First-party CLI/MCP sources retain client identity, the pinned organization boundary and source expiry. Protected local tooling replaces returned credentials with topolo-secret references; preserve the reference unchanged for a compatible next action, never reveal or persist its underlying token, and release it through the published secret-release operation after use.
Cookie-authenticated Chat creation requires X-Topolo-Auth: 1, live session/refresh records and matching X-CSRF-Token from the surface read. It neither rotates cookies nor extends the original sign-in. Revoked or expired browser records cannot be used for recovery.
Inspect account_id, appId and per-context resources, then read surface_sessions.get with the same app_id and source credential. Target operations independently recheck membership and consent. Discard the credential when finished; no persistent grant was created. Use a separately discovered authorized session revocation only if sign-in compromise requires it.
Run the action
Write the discovered application id to payload.json. Validate and plan the unchanged input. Creation is a mutation: execute only after the human has authorized this credential operation; --confirm acknowledges that authorization.
topolo actions validate app_topolo_auth.surface_sessions.create --data @payload.json --json
topolo actions plan app_topolo_auth.surface_sessions.create --data @payload.json --confirm --json
topolo actions call app_topolo_auth.surface_sessions.create --data @payload.json --confirm --detail --json
MCP uses topolo_validate_action and topolo_plan_action for the same input, followed by topolo_call_action with confirm=true after authorization.
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_auth.surface_sessions.create",
"input": {
"app_id": "app_topolo_chat"
},
"confirm": true
}
}
Worked responses
Every example uses synthetic identities and a fixed clock. Cookie/browser and credential state described in a title is a fixture precondition, not an extra action-input field. Responses below are the raw handler envelope; protected tooling may replace returned credential values with opaque references.
Verified account retains personal history context and only the currently authorized Alpha workspace
Input · payload.json:
{
"app_id": "app_topolo_chat"
}
Captured local handler response · HTTP 200:
{
"success": true,
"message": "Surface session created",
"data": {
"account_id": "usr_surface_fixture",
"access_token": "synthetic-unusable-surface-token",
"token_type": "Bearer",
"expires_in": 300,
"surface_session": {
"version": 1,
"appId": "app_topolo_chat",
"contexts": [
{
"type": "personal",
"id": "usr_surface_fixture",
"label": "Personal",
"slug": null,
"role": "account",
"permissions": [],
"resources": []
},
{
"type": "organization",
"id": "org_surface_alpha",
"label": "Alpha fixture",
"slug": "alpha-fixture",
"role": "member",
"permissions": [
"direct_messages:read"
],
"resources": [
{
"type": "workspace",
"id": "ws_surface_alpha",
"label": "Alpha workspace",
"slug": "alpha-workspace",
"isDefault": true,
"accessLevel": "read_write"
}
]
}
]
}
},
"timestamp": "2026-10-05T00:00:00.000Z"
}
Verified account retains personal history context and only the currently authorized Alpha workspace. The response uses synthetic unusable signing output; compatible protected CLI/MCP replaces a real credential with an opaque secret reference.
Revoked work membership leaves a personal context with no workspace grants
Input · payload.json:
{
"app_id": "app_topolo_chat"
}
Captured local handler response · HTTP 200:
{
"success": true,
"message": "Surface session created",
"data": {
"account_id": "usr_surface_fixture",
"access_token": "synthetic-unusable-surface-token",
"token_type": "Bearer",
"expires_in": 300,
"surface_session": {
"version": 1,
"appId": "app_topolo_chat",
"contexts": [
{
"type": "personal",
"id": "usr_surface_fixture",
"label": "Personal",
"slug": null,
"role": "account",
"permissions": [],
"resources": []
}
]
}
},
"timestamp": "2026-10-05T00:00:00.000Z"
}
Revoked work membership leaves a personal context with no workspace grants. The response uses synthetic unusable signing output; compatible protected CLI/MCP replaces a real credential with an opaque secret reference.
First-party context-RBAC credential retains its Alpha organization boundary
Input · payload.json:
{
"app_id": "app_topolo_chat"
}
Captured local handler response · HTTP 200:
{
"success": true,
"message": "Surface session created",
"data": {
"account_id": "usr_surface_fixture",
"access_token": "synthetic-unusable-surface-token",
"token_type": "Bearer",
"expires_in": 90,
"surface_session": {
"version": 1,
"appId": "app_topolo_chat",
"contexts": [
{
"type": "personal",
"id": "usr_surface_fixture",
"label": "Personal",
"slug": null,
"role": "account",
"permissions": [],
"resources": []
},
{
"type": "organization",
"id": "org_surface_alpha",
"label": "Alpha fixture",
"slug": "alpha-fixture",
"role": "member",
"permissions": [
"direct_messages:read"
],
"resources": [
{
"type": "workspace",
"id": "ws_surface_alpha",
"label": "Alpha workspace",
"slug": "alpha-workspace",
"isDefault": true,
"accessLevel": "read_write"
}
]
}
]
}
},
"timestamp": "2026-10-05T00:00:00.000Z"
}
First-party context-RBAC credential retains its Alpha organization boundary. The response uses synthetic unusable signing output; compatible protected CLI/MCP replaces a real credential with an opaque secret reference.
Live browser session and refresh record with matching existing CSRF nonce
Input · payload.json:
{
"app_id": "app_topolo_chat"
}
Captured local handler response · HTTP 200:
{
"success": true,
"message": "Surface session created",
"data": {
"account_id": "usr_surface_fixture",
"access_token": "synthetic-unusable-surface-token",
"token_type": "Bearer",
"expires_in": 300,
"surface_session": {
"version": 1,
"appId": "app_topolo_chat",
"contexts": [
{
"type": "personal",
"id": "usr_surface_fixture",
"label": "Personal",
"slug": null,
"role": "account",
"permissions": [],
"resources": []
},
{
"type": "organization",
"id": "org_surface_alpha",
"label": "Alpha fixture",
"slug": "alpha-fixture",
"role": "member",
"permissions": [
"direct_messages:read"
],
"resources": [
{
"type": "workspace",
"id": "ws_surface_alpha",
"label": "Alpha workspace",
"slug": "alpha-workspace",
"isDefault": true,
"accessLevel": "read_write"
}
]
}
]
}
},
"timestamp": "2026-10-05T00:00:00.000Z"
}
Live browser session and refresh record with matching existing CSRF nonce. The response uses synthetic unusable signing output; compatible protected CLI/MCP replaces a real credential with an opaque secret reference.
Verify the result
-
Read surface_sessions.get with the same app_id and credential. Match account_id and the application; each workspace must remain within the returned context.
-
Projection metadata grants neither messaging entitlement nor conversation membership. Resource operations must recheck current authorisation.
Errors and recovery
An API key cannot substitute for a human source credential
Input:
{
"app_id": "app_topolo_chat"
}
Captured local refusal · HTTP 403:
{
"success": false,
"error": {
"message": "A human sign-in is required",
"code": "FORBIDDEN",
"details": null,
"timestamp": "2026-10-05T00:00:00.000Z"
}
}
Token version predates current account revocation
Input:
{
"app_id": "app_topolo_chat"
}
Captured local refusal · HTTP 401:
{
"success": false,
"error": {
"message": "Invalid or revoked account session",
"code": "AUTH_ERROR",
"details": null,
"timestamp": "2026-10-05T00:00:00.000Z"
}
}
Unverified account without a work context has no available Chat surface
Input:
{
"app_id": "app_topolo_chat"
}
Captured local refusal · HTTP 403:
{
"success": false,
"error": {
"message": "User does not have access to this surface in any context",
"code": "FORBIDDEN",
"details": null,
"timestamp": "2026-10-05T00:00:00.000Z"
}
}
Canonical-looking identifier is not a registered application
Input:
{
"app_id": "app_unknown_fixture"
}
Captured local refusal · HTTP 400:
{
"success": false,
"error": {
"message": "app_id is not registered",
"code": "VALIDATION_ERROR",
"details": {
"app_id": true
},
"timestamp": "2026-10-05T00:00:00.000Z"
}
}
An organization selector cannot widen or change the credential
Input:
{
"app_id": "app_topolo_chat",
"orgId": "org_surface_beta"
}
Captured local refusal · HTTP 400:
{
"success": false,
"error": {
"message": "Supply one registered app_id only",
"code": "VALIDATION_ERROR",
"details": {
"app_id": true
},
"timestamp": "2026-10-05T00:00:00.000Z"
}
}
Unavailable workspace policy is an error, not an empty grant
Input:
{
"app_id": "app_topolo_chat"
}
Captured local refusal · HTTP 503:
{
"success": false,
"error": {
"message": "Account surface is temporarily unavailable",
"code": "SURFACE_UNAVAILABLE",
"details": null,
"timestamp": "2026-10-05T00:00:00.000Z"
}
}
Revoked browser refresh record cannot renew or recover sign-in
Input:
{
"app_id": "app_topolo_chat"
}
Captured local refusal · HTTP 401:
{
"success": false,
"error": {
"message": "Browser sign-in revoked or expired",
"code": "AUTH_ERROR",
"details": null,
"timestamp": "2026-10-05T00:00:00.000Z"
}
}
A surface credential cannot mint another surface credential
Input:
{
"app_id": "app_topolo_chat"
}
Captured local refusal · HTTP 400:
{
"success": false,
"error": {
"message": "Surface sessions cannot mint surface sessions",
"code": "VALIDATION_ERROR",
"details": {
"token": true
},
"timestamp": "2026-10-05T00:00:00.000Z"
}
}
Cookie creation without matching CSRF proof is refused
Input:
{
"app_id": "app_topolo_chat"
}
Captured local refusal · HTTP 403:
{
"success": false,
"error": {
"message": "Browser request verification required",
"code": "FORBIDDEN",
"details": null,
"timestamp": "2026-10-05T00:00:00.000Z"
}
}
Expired first-party source cannot issue a new surface credential
Input:
{
"app_id": "app_topolo_chat"
}
Captured local refusal · HTTP 403:
{
"success": false,
"error": {
"message": "A current first-party account credential is required",
"code": "FORBIDDEN",
"details": null,
"timestamp": "2026-10-05T00:00:00.000Z"
}
}
-
AUTH_ERROR(HTTP 401): Sign in normally after expiry or revocation. A stale refresh credential cannot recover a session. -
FORBIDDEN(HTTP 403): Use a first-party human credential for the requested surface. Cookie creation requires the matching CSRF token from the credentialed surface read. Do not switch context to bypass denial. -
VALIDATION_ERROR(HTTP 400): Discover the application and supply only app_id. A surface token cannot mint another surface token. -
SURFACE_UNAVAILABLE(HTTP 503): Retry the same request when Auth is available; do not infer an access grant from failure.
Tooling error categories
CLI/MCP may separately report authentication_required, permission_denied, rate_limited, invalid_input or dependency_unavailable. These are tooling/catalog categories; preserve the underlying handler code and status shown above when deciding recovery. Do not assume a handler emitted a tooling category.
Recovery boundary
No persistent grants are created. Discard the returned credential; it expires within five minutes. Use published session revocation for a compromised browser sign-in. Creation never restores a revoked session or former organisation access.
Evidence
Existing isolated handlers; no live session, credential, membership, entitlement or provider was changed.
Actual dependencies: HTTP response serialization and strict input validation; Account identity, token-version and CSRF policy checks; Surface projection and TTL issuer calculation; Portable entitlement SQL evaluated by SQLite.
Simulated dependencies: Access/refresh credential verification and synthetic unusable signing output; Registry, hydrated identity, workspace and permission repositories; Seat-policy decision; minimal entitlement schema is not the full migration database; Fixed clock and deliberately synthetic records.
These captures prove existing handler serialization and selected policy branches with disclosed simulations. They do not prove live signing, production grants, multi-D1 consistency or a real cookie/JWT authentication journey. No business credential operation was executed.