identity

package
v0.10.17 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package identity derives per-app identity keys, sanitizes group lists for header transport, and mints the signed identity token the proxy forwards to app processes. See docs/identity.md for the trust model.

Index

Constants

View Source
const (
	HeaderUser            = "X-Shinyhub-User"
	HeaderUserID          = "X-Shinyhub-User-Id"
	HeaderRole            = "X-Shinyhub-Role"
	HeaderAppRole         = "X-Shinyhub-App-Role"
	HeaderEmail           = "X-Shinyhub-Email"
	HeaderName            = "X-Shinyhub-Name"
	HeaderGroups          = "X-Shinyhub-Groups"
	HeaderGroupsTruncated = "X-Shinyhub-Groups-Truncated"
	HeaderToken           = "X-Shinyhub-Identity-Token"

	// HeaderPrefix is the reserved platform prefix: every inbound request
	// header matching it is deleted unconditionally before forwarding.
	HeaderPrefix = "X-Shinyhub-"
)

Header names injected by the proxy. The X-Shinyhub- prefix is stripped from every inbound request before injection, so apps can trust these arrived from the proxy (and verify the token for anything security-sensitive).

View Source
const Issuer = "shinyhub"

Issuer is the iss claim of every identity token.

View Source
const MaxGroups = 100

MaxGroups caps the group list in both the plain header and the JWT claim, bounding per-request header size (enterprise users can carry hundreds of groups; unbounded forwarding blows typical 8-16 KB backend header limits).

View Source
const TokenTTL = 5 * time.Minute

TokenTTL bounds replay of a captured token. Apps verify exp with leeway.

Variables

This section is empty.

Functions

func DeriveKey

func DeriveKey(authSecret string, appID int64) []byte

DeriveKey derives the 32-byte per-app HMAC key from the auth secret. The derivation cannot fail in practice; the underlying helper panics if it ever does.

func MintToken

func MintToken(key []byte, p TokenParams) (string, error)

MintToken signs a short-lived HS256 identity token with the app's key.

func SanitizeGroups

func SanitizeGroups(groups []string) (string, []string, bool)

SanitizeGroups prepares a group list for transport: sorts (deterministic cap), caps at MaxGroups, and joins for the plain header with comma-bearing names OMITTED (a group named "team,admins" must not forge membership for apps that split the header). The JWT claim slice keeps comma-bearing names. Returns (headerValue, claimGroups, truncated).

Types

type GroupsSource

type GroupsSource interface {
	GetUserGroups(userID int64) ([]string, error)
}

GroupsSource is kept as the historical name for the groups half of Source.

type Payload

type Payload struct {
	Username        string
	UserID          string
	Role            string
	AppRole         string
	Email           string
	Name            string
	GroupsHeader    string
	GroupsTruncated bool
	Token           string
}

Payload is everything the proxy injects for one authenticated request.

type Provider

type Provider struct {
	// contains filtered or unexported fields
}

Provider assembles identity payloads: it resolves the user's IdP groups and per-app role through small TTL caches (single-flight per key), sanitizes them, and mints the per-app token. One Provider serves the whole process.

func NewProvider

func NewProvider(authSecret string, src Source) *Provider

func (*Provider) PayloadFor

func (p *Provider) PayloadFor(user *auth.ContextUser, slug string, appID int64) *Payload

PayloadFor builds the identity payload for one request. It never fails: a groups lookup error yields an empty group list (the advisory payload must not take a request down), and a minting error yields a payload with an empty Token (logged).

type Source added in v0.10.0

type Source interface {
	GetUserGroups(userID int64) ([]string, error)
	// AppMembershipForUser reports whether the user owns the app and their
	// effective member role ("manager"/"viewer"/"", the highest of the manual
	// membership and any group rule).
	AppMembershipForUser(slug string, userID int64) (isOwner bool, memberRole string, err error)
}

Source is the subset of the DB store the provider needs: the user's IdP group snapshot and their per-app membership (owner / member role).

type TokenClaims

type TokenClaims struct {
	Role string `json:"role"`
	// AppRole is the caller's capability on THIS app: "owner", "manager"
	// (global admin/operator or a manager-role member/group), or "viewer".
	// Empty when the membership lookup was unavailable.
	AppRole           string   `json:"app_role,omitempty"`
	Email             string   `json:"email,omitempty"`
	Name              string   `json:"name,omitempty"`
	Groups            []string `json:"groups"`
	GroupsTruncated   bool     `json:"groups_truncated,omitempty"`
	PreferredUsername string   `json:"preferred_username"`
	jwt.RegisteredClaims
}

TokenClaims is the identity token payload. Apps verify iss, aud (their own slug, injected as SHINYHUB_APP_SLUG), signature, and exp with ~30 s leeway.

type TokenParams

type TokenParams struct {
	UserID          int64
	Username        string
	Role            string
	AppRole         string   // per-app capability; empty = unavailable
	Email           string   // empty when the upstream IdP provided none
	Name            string   // display name; empty when the IdP provided none
	Groups          []string // pre-sanitized claim slice from SanitizeGroups
	GroupsTruncated bool
	Slug            string // becomes aud
}

TokenParams carries everything MintToken stamps into the claims.

Jump to

Keyboard shortcuts

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