Documentation
¶
Index ¶
- Constants
- func AppAuthMiddleware(deps *Deps) func(http.Handler) http.Handler
- func CallbackHandler(deps *Deps) http.HandlerFunc
- func ContextWithCaller(ctx context.Context, c *CallerIdentity) context.Context
- func ContextWithUser(ctx context.Context, u *AuthenticatedUser) context.Context
- func EncodeSessionToken(claims *SessionTokenClaims, key *SigningKey) (string, error)
- func GeneratePAT() (plaintext string, hash []byte, err error)
- func HashPAT(plaintext string) []byte
- func LoginHandler(deps *Deps) http.HandlerFunc
- func LogoutHandler(deps *Deps) http.HandlerFunc
- func NowUnix() int64
- type AuthSource
- type AuthenticatedUser
- type CallerIdentity
- type CookiePayload
- type Deps
- type OIDCClient
- func (c *OIDCClient) AuthCodeURL(state string, nonce string) string
- func (c *OIDCClient) EndSessionEndpoint() string
- func (c *OIDCClient) Exchange(ctx context.Context, code string) (*oauth2.Token, *oidc.IDToken, map[string]json.RawMessage, error)
- func (c *OIDCClient) JWKSURI() string
- func (c *OIDCClient) RefreshToken(ctx context.Context, refreshToken string) (*oauth2.Token, error)
- type Role
- type SessionTokenClaims
- type SigningKey
- type UserSession
- type UserSessionStore
- func (s *UserSessionStore) Delete(sub string)
- func (s *UserSessionStore) Get(sub string) *UserSession
- func (s *UserSessionStore) RefreshLock(sub string) *sync.Mutex
- func (s *UserSessionStore) Set(sub string, session *UserSession)
- func (s *UserSessionStore) UpdateTokens(sub, accessToken string, refreshToken *string, expiresAt int64) bool
Constants ¶
const SessionTokenTTL = 5 * time.Minute
SessionTokenTTL is the validity window for session reference tokens.
Variables ¶
This section is empty.
Functions ¶
func AppAuthMiddleware ¶
AppAuthMiddleware authenticates if possible, but does not require it. Public apps allow unauthenticated access; the proxy handler decides whether to allow or deny based on the app's access_type.
When OIDC is not configured (v0 compat), the middleware passes all requests through unchanged (no identity in context).
func CallbackHandler ¶
func CallbackHandler(deps *Deps) http.HandlerFunc
CallbackHandler handles the IdP callback after user authentication.
func ContextWithCaller ¶
func ContextWithCaller(ctx context.Context, c *CallerIdentity) context.Context
ContextWithCaller returns a new context carrying the given CallerIdentity.
func ContextWithUser ¶
func ContextWithUser(ctx context.Context, u *AuthenticatedUser) context.Context
ContextWithUser returns a new context carrying the given AuthenticatedUser.
func EncodeSessionToken ¶
func EncodeSessionToken(claims *SessionTokenClaims, key *SigningKey) (string, error)
EncodeSessionToken serializes and signs a session reference token. Format: base64url(json) + "." + base64url(hmac)
func GeneratePAT ¶
GeneratePAT creates a new personal access token with the by_ prefix. Returns the plaintext token (shown once to the user) and its SHA-256 hash (stored in the database).
func LoginHandler ¶
func LoginHandler(deps *Deps) http.HandlerFunc
LoginHandler initiates the OIDC authorization code flow. Query params: ?return_url=/app/my-app/ (optional, default: /)
func LogoutHandler ¶
func LogoutHandler(deps *Deps) http.HandlerFunc
LogoutHandler clears the session cookie and removes the server-side session. Redirects to / (or to the IdP's end_session_endpoint if available).
Types ¶
type AuthSource ¶
type AuthSource int
AuthSource describes how the caller authenticated.
const ( AuthSourceSession AuthSource = iota // Browser session via OIDC AuthSourcePAT // Personal Access Token )
type AuthenticatedUser ¶
AuthenticatedUser represents a validated user identity extracted from a session. Stored in the request context by the auth middleware.
func UserFromContext ¶
func UserFromContext(ctx context.Context) *AuthenticatedUser
UserFromContext retrieves the AuthenticatedUser from the request context, or nil if not present.
type CallerIdentity ¶
type CallerIdentity struct {
Sub string
Name string // human-readable display name (from OIDC name claim / DB)
Role Role
Source AuthSource
}
CallerIdentity is the unified caller identity produced by auth middlewares. Stored in request context for use by authorization checks.
func CallerFromContext ¶
func CallerFromContext(ctx context.Context) *CallerIdentity
CallerFromContext extracts the CallerIdentity from the context. Returns nil if no identity is present.
func (*CallerIdentity) DisplayName ¶
func (c *CallerIdentity) DisplayName() string
DisplayName returns the human-readable name if available, otherwise the Sub.
type CookiePayload ¶
CookiePayload is the minimal payload encoded into the session cookie. Signed with HMAC-SHA256. All other session data lives server-side.
func DecodeCookie ¶
func DecodeCookie(value string, key *SigningKey) (*CookiePayload, error)
DecodeCookie verifies the HMAC signature and deserializes the payload.
func (*CookiePayload) Encode ¶
func (p *CookiePayload) Encode(key *SigningKey) (string, error)
Encode serializes the payload and signs it with HMAC-SHA256. Format: base64url(json) + "." + base64url(hmac)
type Deps ¶
type Deps struct {
Config *config.Config
OIDCClient *OIDCClient
SigningKey *SigningKey
UserSessions *UserSessionStore
AuditLog *audit.Log
DB *db.DB
}
Deps carries the dependencies that auth handlers and middleware need. Constructed in the router layer from the server struct, avoiding a circular import between auth and server.
type OIDCClient ¶
type OIDCClient struct {
// contains filtered or unexported fields
}
OIDCClient wraps the go-oidc provider and oauth2 config. Initialized once at server startup via Discover().
func Discover ¶
func Discover(ctx context.Context, issuerURL, discoveryURL, clientID, clientSecret, redirectURL string) (*OIDCClient, error)
Discover performs OIDC discovery against the issuer URL and returns a configured client ready for the authorization code flow.
If discoveryURL is non-empty, OIDC discovery is performed against that URL instead of issuerURL. This is useful in Docker environments where the IdP is reachable at a different internal address (e.g. http://dex:5556) than the public issuer URL used in tokens (e.g. http://localhost:5556). A custom HTTP transport rewrites all server-side requests to use the internal address. Token issuer validation still uses issuerURL.
func (*OIDCClient) AuthCodeURL ¶
func (c *OIDCClient) AuthCodeURL(state string, nonce string) string
AuthCodeURL generates the authorization URL with a random state and nonce.
func (*OIDCClient) EndSessionEndpoint ¶
func (c *OIDCClient) EndSessionEndpoint() string
EndSessionEndpoint returns the IdP's end_session_endpoint if advertised in discovery metadata, or empty string otherwise.
func (*OIDCClient) Exchange ¶
func (c *OIDCClient) Exchange(ctx context.Context, code string) (*oauth2.Token, *oidc.IDToken, map[string]json.RawMessage, error)
Exchange trades an authorization code for tokens.
func (*OIDCClient) JWKSURI ¶
func (c *OIDCClient) JWKSURI() string
JWKSURI returns the IdP's jwks_uri from discovery metadata.
func (*OIDCClient) RefreshToken ¶
RefreshToken exchanges a refresh token for a new access token.
type Role ¶
type Role int
Role is a system-level role managed directly in blockyard's users table. Ordered by privilege — higher value means more privilege.
func (Role) CanCreateApp ¶
CanCreateApp reports whether this role can create new apps.
func (Role) CanManageRoles ¶
CanManageRoles reports whether this role can manage users.
func (Role) CanManageTags ¶
CanManageTags reports whether this role can create or delete tags.
func (Role) CanViewAllApps ¶
CanViewAllApps reports whether this role can see all apps regardless of ownership or grants.
type SessionTokenClaims ¶
type SessionTokenClaims struct {
Sub string `json:"sub"` // user subject
App string `json:"app"` // app ID
Wid string `json:"wid"` // worker ID
Iat int64 `json:"iat"` // issued at (unix seconds)
Exp int64 `json:"exp"` // expiry (unix seconds)
}
SessionTokenClaims is the payload of a session reference token. Issued by the proxy on each request to shared containers. The app exchanges this for real credentials via the credential exchange API.
func DecodeSessionToken ¶
func DecodeSessionToken(token string, key *SigningKey) (*SessionTokenClaims, error)
DecodeSessionToken verifies the HMAC signature and deserializes the claims. Returns an error if the signature is invalid or the token has expired.
type SigningKey ¶
type SigningKey struct {
// contains filtered or unexported fields
}
SigningKey holds the derived HMAC key for cookie signing.
func DeriveSessionTokenKey ¶
func DeriveSessionTokenKey(secret string) *SigningKey
DeriveSessionTokenKey derives a signing key for session tokens. Uses a different domain string than cookie signing to prevent cross-protocol token confusion.
func DeriveSigningKey ¶
func DeriveSigningKey(secret string) *SigningKey
DeriveSigningKey derives a signing key from a secret using HMAC with a domain separation string.
func NewSigningKey ¶ added in v0.0.3
func NewSigningKey(key []byte) *SigningKey
NewSigningKey creates a signing key from raw bytes. Used for ephemeral keys generated from crypto/rand.
type UserSession ¶
type UserSession struct {
AccessToken string
RefreshToken string
ExpiresAt int64 // unix timestamp
}
UserSession holds per-user session data stored server-side. Keyed by sub.
func EnsureFreshToken ¶
EnsureFreshToken checks if the user's access token is near expiry (within 60 seconds) and refreshes it if needed. Returns the current session, or an error if refresh fails. Thread-safe via per-user locks.
type UserSessionStore ¶
type UserSessionStore struct {
// contains filtered or unexported fields
}
UserSessionStore is an in-memory session store protected by a RWMutex.
func NewUserSessionStore ¶
func NewUserSessionStore() *UserSessionStore
NewUserSessionStore creates an empty session store.
func (*UserSessionStore) Delete ¶
func (s *UserSessionStore) Delete(sub string)
Delete removes a user's session (on logout).
func (*UserSessionStore) Get ¶
func (s *UserSessionStore) Get(sub string) *UserSession
Get looks up a user's session by sub. Returns nil if not found.
func (*UserSessionStore) RefreshLock ¶
func (s *UserSessionStore) RefreshLock(sub string) *sync.Mutex
RefreshLock returns the per-user mutex for token refresh. Creates one if it does not exist.
func (*UserSessionStore) Set ¶
func (s *UserSessionStore) Set(sub string, session *UserSession)
Set inserts or replaces the session for a user.
func (*UserSessionStore) UpdateTokens ¶
func (s *UserSessionStore) UpdateTokens(sub, accessToken string, refreshToken *string, expiresAt int64) bool
UpdateTokens updates the access/refresh tokens after a refresh. Returns false if the session does not exist.