1. concepts
temper
  • Temper documentation
  • cli
    • README
    • admin
    • auth
    • check
    • cogmap
    • config
    • context
    • edge
    • init
    • invitations
    • invocation
    • memory
    • pull
    • query
    • resource
    • search
    • skill
    • slack
    • status
    • steward
    • team
    • trail
    • update
    • version
    • warmup
  • config
    • README
  • auth
  • guides
  • doors
    • Building against Temper
    • Running Temper
    • Using Temper
  • concepts
    • Auth Identity
    • Authoring Authorization
    • Contexts and Refs
    • Machine Tokens
    • Operational Memory
    • Release Verification
    • The SAML Reconcile Channel
    • Slack Identity and Revocation
    • Teams and Roles
    • Telemetry
    • Token Verification
    • The Trust Boundary
  • playbooks
    • Adopt operational memory
    • Authenticate
    • Bootstrap an Org
    • Bootstrap a Team's Self-Cognition
    • Build a cognitive map
    • Connect Claude Code
    • Connect Temper to Claude Desktop
    • Deliver L0 Kernel Content
    • Deploy a Steward Agent
    • Deploy the Web UI
    • Enterprise Install
    • Provision a Read-Only GitHub Connection
    • Ingest a corpus
    • Install Temper
    • Run a Team
    • Self-Host Temper
    • Self-host Temper with Okta
    • Self-host Temper with a SAML IdP
    • Send traces to an OTLP backend
    • Slack Mentions
    • Standing Up a Machine Credential
  • sdks
    • Integrating Ruby with temper-rb
  • Temper Cloud API
    • Access
      • POST /api/access/requests — submit a join request for the gating team.
      • GET /api/access/requests/me — check own join request status.
      • DELETE /api/access/requests/me — withdraw a pending join request.
      • POST /api/access/reviews — a revoked principal asks an admin to reconsider (spec D15).
      • GET /api/access/settings — read public system settings.
    • Slack Link
      • Disconnect any principal. Operator path — offboarding and stuck users.
      • Disconnect EVERY Slack principal bound to the caller's own profile.
    • Auditor
      • auditor_dispatch
      • auditor_sweep
      • complete_auditor_job
    • Graph
      • POST /api/cogmaps/{id}/graph/slice — R4 cogmap-scoped neighborhood slice.
      • GET /api/graph/cogmaps/{id}/panorama — enter-a-cogmap Tier-0 interior.
      • GET /api/graph/contexts/composition — Beat E Tier-1: the force-graph composition of a container's (or a residual bucket's) members.
      • GET /api/graph/contexts/panorama — Beat E Tier-0: goal-container territories + residual tray.
      • GET /api/graph/home — the you→teams→cogmaps membership home.
      • GET /api/graph/regions/composition — Beat D region→resources composition drill.
    • Cognitive Maps
      • list_cognitive_maps
      • genesis
      • get_cognitive_map
      • reconcile
      • analytics
      • grant_cogmap_access
      • revoke_cogmap_access
      • materialize
      • materialize_delta
      • region_metrics
      • shape
      • bind_team
      • unbind_team
    • Contexts
      • list_contexts
      • create_context
      • get_context
      • context_materialize
      • reassign
      • context_region_metrics
      • rename
      • context_shape
      • share_team
      • unshare_team
    • Events
      • cursor
      • GET /api/graph/elements/{kind}/{id}/trail — R5 element event-trail. kind ∈ {node, edge}.
    • Facets
      • set_facet
      • Read the live facets of one edge.
      • Set a facet whose owner is an **edge** rather than a resource.
      • Read the live facets of one resource — the confirming read for a write that steers region formation and Atlas grouping.
    • Health
      • health_check
    • Ingest
      • create_ingest
      • update_ingest
      • list_blocks
      • append_block
      • finalize_resource
    • Invitations
      • accept
      • decline
      • list_mine
      • list_team_invitations
      • revoke_team_invitation
      • create_team_invitation
    • Invocations
      • list_invocations
      • open
      • show
      • close
    • Profile
      • get_profile
      • update_profile
      • list_auth_links
    • Query
      • `POST /api/query`.
    • Relationships
      • assert
      • fold
      • retype
      • reweight
    • Resources
      • `GET /api/resources` — **one response type, unconditionally.**
      • create_resource
      • get_resource
      • delete_resource
      • update_resource
      • List the finding at `{id}`'s citation-audit trail — one row per audit, each naming its auditor.
      • Record an auditor's signed defensibility verdict on one `(block, source)` citation of the finding at `{id}`. CONFORM to `handlers::edges::assert` (the sibling authored-write handler): thin — build the command, dispatch it, map the error. No persistence he
      • get_content
      • list_resource_edges
      • resource_evidence
      • grant_resource_access
      • revoke_resource_access
      • resource_lineage
      • provenance
      • annotate_resource
    • Meta
      • get_meta
      • update_meta
    • Reassign
      • reassign_resource
      • reassign_team
    • Search
      • `POST /api/search`.
    • Steward
      • candidates
      • dispatch
      • sweep
      • delta
      • advance
    • Teams
      • list_teams
      • create_team
      • detail
      • delete_team
      • update_team
      • add_member
      • remove_member
      • change_role
    • Schemas
      • AcceptInvitationResponse
      • ActInput
      • ActInvocation
      • ActName
      • ActQuantity
      • ActRefusal
      • ActorAuthority
      • AddMemberRequest
      • AdvanceWatermarkAck
      • AdvanceWatermarkRequest
      • AgentAuthorship
      • AppendBlockPayload
      • AssertRelationshipRequest
      • AtlasEdge
      • AtlasHome
      • AtlasNode
      • AtlasSubgraph
      • AuditCitation
      • AuditSweepRow
      • AuditorDispatchTickRequest
      • AuditorDispatchTickResponse
      • AuditorJobCompleteAck
      • BindTeamOutcome
      • BindTeamRequest
      • BlockId
      • BlockProvenanceRow
      • BlocksResponse
      • BodyStorage
      • Bridge
      • BulkReassignAck
      • BulkReassignRequest
      • ChangeRoleRequest
      • CharterBlock
      • CharterDisposition
      • CitationAuditRequest
      • CitationAuditRow
      • ClaimedAuditJob
      • ClaimedJob
      • CloseInvocationRequest
      • CogmapAnalyticsRow
      • CogmapDetail
      • CogmapFoundationRow
      • CogmapGrantBody
      • CogmapId
      • CogmapRegionMetricsRow
      • CogmapRegionRow
      • CogmapRegulationRow
      • CogmapRevokeBody
      • CogmapRow
      • CogmapStaleness
      • CombineNode
      • CombineOp
      • Composition
      • CompositionTrace
      • ConfidenceBand
      • ContentResponse
      • ContextCreateRequest
      • ContextId
      • ContextOwnerRef
      • ContextPanorama
      • ContextRow
      • ContextRowWithCounts
      • CorrelationId
      • CreateCogmapOutcome
      • CreateCogmapRequest
      • CreateInvitationRequest
      • CreateRequestBody
      • CreateReviewBody
      • DeleteResponse
      • DeviceOverrides
      • DispatchTickRequest
      • DispatchTickResponse
      • Disposition
      • DriftSweepRow
      • EdgeFacetRow
      • EdgeFacetSetRequest
      • EdgeFacetsResponse
      • EdgeFilter
      • EdgeId
      • EdgeKind
      • ElementEvent
      • ElementKind
      • EmbedDispatchSummary
      • Entitlements
      • ErrorBody
      • ErrorDetail
      • ErrorDetails
      • EventCursorResponse
      • EventTrail
      • ExactArm
      • ExactHit
      • Extent
      • FacetAck
      • FacetPredicate
      • FacetSetRequest
      • FinalizePayload
      • FoldRelationshipRequest
      • GrantOutcome
      • GraphEdgeRow
      • GroupKeyMeta
      • HealthResponse
      • HomeCogmap
      • HomeContext
      • IdKind
      • IdProvenance
      • IdSet
      • IdpRevocation
      • IngestCreateResponse
      • IngestDelta
      • IngestPayload
      • IngestState
      • InheritedReadGrant
      • InheritedShare
      • InputSource
      • Intention
      • InvitationStatus
      • InvitationTokenRequest
      • InviteeInvitation
      • InvocationAck
      • InvocationActRow
      • InvocationCloseAck
      • InvocationId
      • InvocationSummary
      • InvocationView
      • JoinRequest
      • JoinRequestStatus
      • LensId
      • LineageNode
      • ManagedMeta
      • MatchLocation
      • MaterializeAck
      • MaterializeDelta
      • MaterializeRequest
      • MergePolicy
      • MetaUpdatePayload
      • NarrowedBy
      • NodeHome
      • OpenInvocationRequest
      • OrdOp
      • OrphanNode
      • OutcomeDeclaration
      • PlanRefusal
      • PlanRefusalDetails
      • Polarity
      • Profile
      • ProfileAuthLink
      • ProfileId
      • ProfileUpdateRequest
      • ProfileWithEntitlements
      • PropertyOp
      • PropertyPredicate
      • ProvenanceSource
      • PublicSystemSettings
      • QuantityScale
      • QueryResponse
      • ReassignAck
      • ReassignContextOutcome
      • ReassignContextRequest
      • ReassignResourceRequest
      • ReconcileCogmapRequest
      • ReconcileEdge
      • ReconcileEdgeTombstone
      • ReconcileEntry
      • ReconcileOutcome
      • ReconcileTelos
      • ReconcileTelosBlock
      • ReconcileTombstone
      • Refusal
      • RefusalReason
      • RegionHit
      • RegionId
      • RelationshipAck
      • RemoveMemberOutcome
      • RenameContextOutcome
      • RenameContextRequest
      • ResidualBucket
      • ResidualContext
      • ResidualGroups
      • ResidualOwnedReach
      • ResourceAnnotateRequest
      • ResourceCreateRequest
      • ResourceFacetRow
      • ResourceFacets
      • ResourceFacetsResponse
      • ResourceFilter
      • ResourceGrantBody
      • ResourceHit
      • ResourceId
      • ResourceLineage
      • ResourceListResponse
      • ResourceRevokeBody
      • ResourceSection
      • ResourceSortField
      • ResourceUpdateRequest
      • ResourceView
      • ReturnSpec
      • RetypeRelationshipRequest
      • RevokeOutcome
      • ReweightRelationshipRequest
      • ScoreKind
      • Scoring
      • SearchParams
      • SearchReason
      • SearchResponse
      • SearchResultRow
      • SearchScope
      • SearchScopeInfo
      • SegmentInfo
      • SegmentedBegin
      • SegmentedBeginResponse
      • ShareContextOutcome
      • ShareContextRequest
      • SlackDisconnectRequest
      • SlackDisconnectResponse
      • SlackDisconnectedPrincipal
      • SliceRequest
      • SortOrder
      • StageDisposition
      • StageInput
      • StageInputTrace
      • StageName
      • StageNode
      • StageOutput
      • StageRelation
      • StageResult
      • StageTrace
      • Standing
      • StandingShape
      • Subscription
      • SubscriptionOverride
      • SystemAccessDetails
      • TeamCreateRequest
      • TeamDetail
      • TeamInvitation
      • TeamMemberDetail
      • TeamMemberRow
      • TeamMemberSource
      • TeamRole
      • TeamRow
      • TeamUpdateRequest
      • Territory
      • TerritoryKind
      • TerritoryOverview
      • UnbindTeamOutcome
      • UnshareContextOutcome
      • VaultConfig
      • ViaEntry
      • WideArm
      • WideHit
  • Temper /api/query — the compositional read surface
    • Run a declared composition of situated acts.
    • Schemas
      • Composition
      • OutcomeDeclaration
      • ReturnSpec
      • Intention
      • StageNode
      • ActInvocation
      • CombineNode
      • StageInput
      • StageRelation
      • Disclosure
      • QueryResponse
      • StageResult
      • StageOutput
      • ScoreKind
      • Scoring
      • ResourceHit
      • CompositionTrace
      • StageTrace
      • InputSource
      • NarrowedBy
      • StageName
      • ActName
      • IdKind
      • IdSet
      • BoundTerm
      • Extent
      • StageDisposition
      • ActRefusal
      • PlanRefusal
      • RefusalReason
      • ActQuantity
      • QuantityScale
      • ResourceFilter
      • EdgeFilter
      • PropertyPredicate
      • PropertyOp
      • ResourceSection
      • EdgeKind
      • OrdOp
      • CogmapId
      • ContextId
      • IdProvenance
      • FacetPredicate
      • CombineOp
      • BlockId
      • MatchLocation
      • BodyStorage
      • ResourceId
      • IngestState
      • ManagedMeta
      • ProfileId
      • ResourceView
      • Polarity
      • ViaEntry
      • LensId
      • RegionId
      • CogmapRegionRow
      • RegionHit
      • StageInputTrace
      • Standing
      • ActorAuthority
      • Refusal
      • SystemAccessDetails
      • PlanRefusalDetails
      • ErrorDetails
      • ErrorDetail
      • ErrorBody
  1. concepts

The Trust Boundary

For integrators — anyone writing code that calls the Temper API, whether a service, a
script, or an agent runtime. Also relevant to operators, who configure the boundary their
deployment enforces.
If you are an individual user authenticating through the CLI, the short version is: install
the binary, run temper init, run temper auth login, then temper auth request-access and
wait for an admin to approve. This page is about what the server enforces, not how to run a
login command.

What the boundary is#

Every call to Temper — HTTP or MCP — crosses the same two-gate boundary, enforced in one place
(the auth seam) and projected onto two surfaces (the HTTP API and the MCP server). A call that
fails either gate is refused before any data is touched.
The two gates, stated as outcomes (not levels):
1.
Authentication (401 on failure). The caller presents a Bearer JWT. The server validates
its signature against exactly one issuer's keys, checks its audience, checks its expiry, and
resolves it to a profile. If any of these fail, the response is 401 UNAUTHORIZED. The
caller fixes the token and retries.
2.
System access (403 on failure). The authenticated profile must have approved standing
on this instance. A brand-new signup is born denied; request-access moves it to
requested; only an admin can move it to approved. If the profile is not approved, the
response is 403 SYSTEM_ACCESS_REQUIRED with a payload explaining why. There is no path from
signup to a successful data call that does not pass through an admin.
Registration is not admission, and nothing fails in between. A machine can register, mint a
token, pass authentication, and be refused only at the system-access gate — on every data call.
Nothing warns earlier. This is the single most valuable thing to know about the boundary if you
are automating against it.

The API base URL#

The API base is <origin>/api — the origin plus an /api prefix the client prepends per
request. For the hosted instance that is https://temperkb.io/api. Verify it live:
GET https://temperkb.io/api/health → 200 (unauthenticated)
The published API reference — every endpoint, every schema, rendered from the router's
OpenAPI spec — is at docs.temperkb.io. Link the site root, not
a deep page; per-endpoint pages have import-generated ids that may not survive a re-import.

How a caller obtains the audience#

The audience is the string the JWT must carry for the server to accept it. Do not guess it;
discover it.
GET <origin>/.well-known/oauth-authorization-server
The response includes a resource field carrying exactly the audience the server validates.
For the hosted instance:
{ "issuer": "https://temperkb.us.auth0.com/",
  "resource": "https://temperkb.io/api" }
On a self-hosted SAML instance (Temper AS), the response has no resource field —
correctly, because that AS ignores a request-supplied audience. The caller omits audience
and the server does too.
The trap. /.well-known/oauth-**protected-resource** (RFC 9728) returns a different
resource — the MCP base URL, not the audience. An integrator who reaches for the wrong
well-known document gets a value that silently fails audience validation. Use
oauth-authorization-server (RFC 8414), not oauth-protected-resource.

The error contract#

Every error response carries {"error":{"code":"…","message":"…","details"?:…}}. The code
is a stable string; details rides only SYSTEM_ACCESS_REQUIRED and PLAN_REFUSED.
statuscodemeanscaller doesretry
401UNAUTHORIZEDmissing or malformed Bearerfix the headerno
401UNAUTHORIZEDinvalid or expired token — signature, issuer, audience, expiryrefresh; re-check audience against discoveryonce
401UNAUTHORIZEDauth service unavailable (JWKS fetch)back offyes
401UNAUTHORIZEDaccount deactivatedstop; contact operatorno
401UNAUTHORIZEDmachine client not registered — message names the exact provision commandhand the client_id to an operatorno
403SYSTEM_ACCESS_REQUIREDauthentic, no approved standing; details.refusal.kind says whichhuman: request-access. machine: an admin must approveno
403FORBIDDENrefused, deliberately message-less (no capability disclosure)obtain the grant out of bandno
403FORBIDDEN_DETAILrefused, message names the capabilityobtain itno
404NOT_FOUNDabsent or masked (a probe is not an existence oracle)infer nothing either wayno
400PLAN_REFUSEDcomposition invalid; details.refusals[] lists every reasonrepair all in one round tripno
422CONTENT_INTEGRITYstored bytes fail the hash; not resumablere-upload from scratchno
500INTERNAL_ERRORserver faultback offyes
MCP collapses all of these to JSON-RPC -32600 with prose — no status, no code, no
details. An integrator writing a service targets HTTP; MCP is an agent-runtime target.

The machine-principal sharp edge#

A machine cannot use the remedy its own 403 advertises. The SYSTEM_ACCESS_REQUIRED
payload includes a cli_command (temper auth request-access), but machines can never
request access — the state transition that moves a profile from denied to requested is
human-only. The only remedy is an admin running temper admin access approve <profile_id>, and
the payload does not name it. State this in any automation you write, because nothing in
the product will.
And it is invisible until it fails: a registered-but-unapproved machine mints a token (200),
passes JWT validation, passes the registration gate, passes authentication — and is refused
only at the system-access gate, on every data call. Nothing warns earlier.

Machine principals and headless sessions#

A machine principal is not a user with a long-lived token; it is its own kind of principal,
registered ahead of time. The authentication path is the same Bearer JWT, minted by the same
issuer, validated by the same two gates. What differs is how the token is obtained — a
machine credential exchange, not a browser login.
A headless CLI session (a cloud agent, a CI pipeline) can authenticate without browser OAuth
by setting environment variables:
VariablePurposeRequired?
TEMPER_TOKENJWT access token for the APIYes
TEMPER_API_URLAPI base URL (e.g. https://temperkb.io/api)Yes — without it the client has no endpoint and fails at send time
TEMPER_PROVIDERAuth provider name that issued the tokenNo — defaults to auth0
TEMPER_DEVICE_IDStable device id for this sessionNo — a fresh UUIDv7 is generated if unset
A human-driven agent (Claude Code, an IDE plugin) authenticates as the human: the human
runs temper auth login, the CLI caches the token, and the agent inherits it by driving the
CLI. There is no separate "agent identity" — the agent is the human, through the CLI.

MCP is a second surface, not a second API#

The MCP server runs on a different base path (/mcp, no /api prefix) with a JSON-RPC
transport, but the authentication is identical — same issuer, same single audience, same two
gates. The difference is transport and tool surface (~26 consolidated tools against 82 REST
paths). An integrator writing a service targets HTTP; MCP is an agent-runtime target. The SDKs
are generated from the OpenAPI spec, i.e. HTTP-only.

Further reading#

What a machine credential is and how to stand one up:
Machine credentials (playbook).
The auth-identity contract operators configure:
Auth identity.
What the architecture fixes vs. what a deployment chooses:
temperkb.io/operating/governance-and-administration.
Modified at 2026-08-20 02:05:41
Previous
Token Verification
Next
Adopt operational memory
Built with