Help us shape the future of Go! Take the 2026 Go Developer Survey

session

package
v0.57.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 26, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package session provides OAuth session management for the authorization server. Sessions link issued access tokens to upstream identity provider tokens, enabling token exchange and refresh operations.

Index

Constants

View Source
const ClientIDClaimKey = "client_id"

ClientIDClaimKey is the JWT claim key for the OAuth client ID. This identifies which client was issued the token.

View Source
const EmailClaimKey = "email"

EmailClaimKey is the JWT claim key for the user's email address. Per OIDC Core Section 5.1.

View Source
const NameClaimKey = "name"

NameClaimKey is the JWT claim key for the user's display name. Per OIDC Core Section 5.1.

View Source
const NoUpstreamSessionClaimKey = "https://toolhive.dev/no_upstream_session"

NoUpstreamSessionClaimKey marks a token this authorization server minted without any link to an upstream IdP login, so no upstream credential exists for it. Today only the RFC 7523 JWT-bearer grant sets it: its subject is a synthetic machine identity (issuer#subject) asserted by a separate trust root, with no end user and no upstream session.

It exists so a resource server can distinguish "this token was deliberately minted without an upstream session" from "this identity was never enriched with upstream credentials" — states that are otherwise indistinguishable, as both leave Identity.UpstreamTokens nil. pkg/authz/authorizers/cedar reads it to decide whether request-token claims may drive policy. The RFC 8693 delegation grant needs no marker: its "act" claim already says so.

The name is collision-resistant per RFC 7519 Section 4.3, so a JWT from another issuer the deployment trusts cannot assert it by accident. It is a private claim; RFC 9068 Section 2.2.3 permits additional claims on an access token.

View Source
const TokenSessionIDClaimKey = "tsid"

TokenSessionIDClaimKey is the JWT claim key for the token session ID. This links JWT access tokens to stored upstream IDP tokens. We use "tsid" instead of "sid" to avoid confusion with OIDC session management which defines "sid" for different purposes (RFC 7519, OIDC Session Management).

View Source
const UpstreamSubjectClaimKey = "https://toolhive.dev/upstream_subject"

UpstreamSubjectClaimKey is the collision-resistant claim name (RFC 7519 §4.2) of the claim that carries the upstream subject a consumer can key on across upstream client registrations. It is emitted together with the RFC 9493 sub_id claim and under the same disclosure policy.

Variables

This section is empty.

Functions

This section is empty.

Types

type Factory

type Factory func(subject, idpSessionID, clientID string) fosite.Session

Factory is a function that creates a new session given subject, IDP session ID, and client ID. This allows storage implementations to create sessions without importing this package directly.

The factory is primarily used during deserialization where the clientID may be empty because the client_id claim is preserved in the JWT claims Extra map from the original serialized session data.

type Session

type Session struct {
	*oauth2.JWTSession

	// UpstreamSessionID links this session to stored upstream IDP tokens.
	// This ID is used to retrieve the IDP tokens from storage.
	UpstreamSessionID string

	// VerifiedUpstream is preserved server-side through code/refresh storage. It
	// becomes the sub_id and upstream subject claims only when policy opts in.
	VerifiedUpstream UpstreamSubject `json:"verified_upstream,omitzero"`
}

Session extends fosite's JWT session with an IDP session reference. This allows the authorization server to link issued tokens to upstream IDP tokens stored separately.

Most methods are provided by the embedded *oauth2.JWTSession. This type adds IDP session tracking and verified upstream identity provenance; Clone() preserves those fields along with the embedded JWT session.

Concurrency: Sessions are designed to be request-scoped and are not safe for concurrent access from multiple goroutines. This follows Fosite's design pattern where sessions are created per-request, populated by handlers, and then persisted to storage. The storage layer is responsible for thread-safe access to stored sessions.

func New

func New(subject, idpSessionID, clientID string, claims UserClaims) *Session

New creates a new Session with the given subject, IDP session ID, client ID, and optional user profile claims.

Parameters:

  • subject: The OAuth subject (user identifier). May be empty for placeholder sessions.
  • idpSessionID: Links to upstream IDP tokens in storage. If provided, it will be included in the JWT claims as "tsid" to allow proxy middleware to look up upstream IDP tokens.
  • clientID: The OAuth client ID. When provided, it will be included in the JWT claims as "client_id" for binding verification per RFC 9068.
  • claims: Optional user profile claims (name, email) from the upstream IDP. Included in the JWT per OIDC Core Section 5.1.

ClientID handling:

  • For token issuance (authorize handler): Pass the client ID to ensure RFC 9068 compliance. The client_id claim will be embedded in the JWT.
  • For token exchange (token handler): May be empty - Fosite copies claims from the stored authorize session, preserving the original client_id.
  • For deserialization: May be empty - the client_id claim is preserved in the JWT claims Extra map from the serialized session data.

Note: The remaining RFC 9068 required claims (iss, aud, exp, iat, jti) are populated by Fosite during token generation. This session only initializes custom claims that are not part of Fosite's standard JWT handling.

func (*Session) ClearSubjectIdentifier added in v0.57.0

func (s *Session) ClearSubjectIdentifier()

ClearSubjectIdentifier removes any persisted or source-token sub_id and upstream subject claim before the current grant decides whether it is eligible to issue them. It mutates the receiver's claims in place; a caller holding a session loaded from storage must Clone it first.

func (*Session) Clone

func (s *Session) Clone() fosite.Session

Clone creates a deep copy of the session. This overrides the embedded JWTSession.Clone() to also copy UpstreamSessionID and the verified upstream identity.

func (*Session) GetIDPSessionID

func (s *Session) GetIDPSessionID() string

GetIDPSessionID returns the IDP session ID.

func (*Session) SetIDPSessionID

func (s *Session) SetIDPSessionID(id string)

SetIDPSessionID sets the IDP session ID.

func (*Session) SetSubjectIdentifier added in v0.57.0

func (s *Session) SetSubjectIdentifier(upstream UpstreamSubject)

SetSubjectIdentifier sets the RFC 9493 sub_id claim and the upstream subject claim from the verified upstream identity. It does nothing unless the identity is complete. It mutates the receiver's claims in place; a caller holding a session loaded from storage must Clone it first.

type UpstreamSession

type UpstreamSession interface {
	oauth2.JWTSessionContainer
	GetIDPSessionID() string
}

UpstreamSession is an interface for sessions that support IDP linking and JWT claims. It embeds oauth2.JWTSessionContainer (which includes fosite.Session, GetJWTClaims, and GetJWTHeader) and adds IDP session tracking. This interface is used by the storage layer for serialization/deserialization.

type UpstreamSubject added in v0.57.0

type UpstreamSubject struct {
	Issuer      string `json:"iss,omitempty"`
	Subject     string `json:"sub,omitempty"`
	StableClaim string `json:"stable_claim,omitempty"`
	StableValue string `json:"stable_value,omitempty"`
}

UpstreamSubject is the verified identity of the upstream OIDC login that established the local user. Issuer and Subject are the exact iss and sub of the validated upstream ID token. StableClaim names the claim the upstream is configured to key users on (its subject_claim, or "sub"), and StableValue is that claim's value from the same ID token. All four are set together or not at all.

upstream.Identity carries the same four values as its Verified* fields, because the upstream package cannot import this one. verifiedUpstreamIdentity in handlers/callback.go converts between them; a member added here must be added there and to upstream.Identity too, or IsComplete never holds and the claims are silently dropped.

func (UpstreamSubject) IsComplete added in v0.57.0

func (u UpstreamSubject) IsComplete() bool

IsComplete reports whether every member is set. Only a complete value is stored or disclosed.

type UserClaims added in v0.11.2

type UserClaims struct {
	// Name is the user's display name (OIDC "name" claim).
	Name string
	// Email is the user's email address (OIDC "email" claim).
	Email string
}

UserClaims holds optional user profile claims from the upstream IDP. Using a struct avoids parameter-ordering mistakes in function signatures that accept multiple string parameters.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL