Documentation
¶
Overview ¶
Package jwt provides JWT token generation and validation utilities.
Index ¶
- Variables
- func GenerateToken(userID, role, secret string, expiry time.Duration) (string, error)
- func GenerateTokenWithExpiry(userID, role, secret string, expiresAt time.Time) (string, error)
- type Claims
- func (c *Claims) GetAccessibleTenantIDs() []string
- func (c *Claims) GetTenantRole(tenantID string) string
- func (c *Claims) HasAllPermissions(permissions ...string) bool
- func (c *Claims) HasAnyPermission(permissions ...string) bool
- func (c *Claims) HasPermission(permission string) bool
- func (c *Claims) HasTenantAccess(tenantID string) bool
- func (c *Claims) HasTenantRole(tenantID string, requiredRole string) bool
- type Generator
- func (g *Generator) GenerateAccessToken(userID, sessionID, role string) (string, time.Time, error)
- func (g *Generator) GenerateAccessTokenWithTenant(userID, email, sessionID string, tenant TenantContext) (string, time.Time, error)
- func (g *Generator) GenerateGlobalRefreshToken(userID, email, name, sessionID string) (string, time.Time, error)
- func (g *Generator) GenerateJobToken(agentID, jobID, tenantID, jobType string, ttl time.Duration, ...) (*JobToken, error)
- func (g *Generator) GenerateRefreshToken(userID, sessionID string) (string, time.Time, error)
- func (g *Generator) GenerateShortLivedToken(userID, tenantID string, ttl time.Duration) (string, error)
- func (g *Generator) GenerateSlimAccessToken(userID, email, name, sessionID string, tenant TenantMembership, ...) (*SlimAccessToken, error)
- func (g *Generator) GenerateTenantScopedAccessToken(userID, email, name, sessionID string, tenant TenantMembership, isAdmin bool) (*TenantScopedAccessToken, error)
- func (g *Generator) GenerateTenantScopedAccessTokenWithPermissions(userID, email, name, sessionID string, tenant TenantMembership, ...) (*TenantScopedAccessToken, error)
- func (g *Generator) GenerateTokenPair(userID, sessionID, role string) (*TokenPair, error)
- func (g *Generator) GenerateTokenPairWithMemberships(userID, email, name, sessionID string, tenants []TenantMembership, ...) (*TokenPair, error)
- func (g *Generator) GenerateTokenPairWithTenant(userID, email, sessionID string, tenant TenantContext) (*TokenPair, error)
- func (g *Generator) ValidateAccessToken(tokenString string) (*Claims, error)
- func (g *Generator) ValidateJobToken(tokenString string) (*JobTokenClaims, error)
- func (g *Generator) ValidateJobTokenForJob(tokenString, expectedAgentID, expectedJobID string) (*JobTokenClaims, error)
- func (g *Generator) ValidateJobTokenWithScope(tokenString string, requiredScope JobTokenScope) (*JobTokenClaims, error)
- func (g *Generator) ValidateRefreshToken(tokenString string) (*Claims, error)
- func (g *Generator) ValidateToken(tokenString string) (*Claims, error)
- type GlobalRefreshTokenResult
- type JobToken
- type JobTokenClaims
- type JobTokenScope
- type SlimAccessToken
- type TenantContext
- type TenantMembership
- type TenantScopedAccessToken
- type TokenConfig
- type TokenPair
- type TokenType
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidToken is returned when the token is invalid. ErrInvalidToken = errors.New("invalid token") // ErrExpiredToken is returned when the token has expired. ErrExpiredToken = errors.New("token has expired") // ErrEmptyUserID is returned when user_id is empty. ErrEmptyUserID = errors.New("user_id cannot be empty") // ErrInvalidTokenType is returned when token type is invalid. ErrInvalidTokenType = errors.New("invalid token type") )
Functions ¶
func GenerateToken ¶
GenerateToken creates a new JWT token with the given claims (legacy support).
Types ¶
type Claims ¶
type Claims struct {
// User identification
UserID string `json:"id"` // User's unique identifier
Email string `json:"email"` // User's email address
Name string `json:"name,omitempty"` // User's display name
SessionID string `json:"session_id,omitempty"`
TokenType TokenType `json:"token_type,omitempty"`
// Multi-tenant access control
Tenants []TenantMembership `json:"tenants,omitempty"` // All tenant memberships
TenantID string `json:"tenant,omitempty"` // Current tenant context (deprecated, use Tenants)
Role string `json:"role,omitempty"` // Global role (admin, user)
Permissions []string `json:"permissions,omitempty"` // Global permissions (deprecated for slim tokens)
IsAdmin bool `json:"admin,omitempty"` // Whether user is a system admin (deprecated for slim tokens)
// Permission version for real-time sync (NEW)
// When this doesn't match Redis version, permissions are stale
// Frontend should refresh permissions via GET /api/v1/me/permissions
PermVersion int `json:"pv,omitempty"`
jwt.RegisteredClaims
}
Claims represents the JWT claims structure. Supports tenant-based access with granular permissions.
func ValidateToken ¶
ValidateToken validates the token and returns the claims.
func (*Claims) GetAccessibleTenantIDs ¶
GetAccessibleTenantIDs returns all tenant IDs the user has access to.
func (*Claims) GetTenantRole ¶
GetTenantRole returns the user's role in a specific tenant.
func (*Claims) HasAllPermissions ¶
HasAllPermissions checks if the claims include all specified permissions.
func (*Claims) HasAnyPermission ¶
HasAnyPermission checks if the claims include any of the specified permissions.
func (*Claims) HasPermission ¶
HasPermission checks if the claims include a specific permission.
func (*Claims) HasTenantAccess ¶
HasTenantAccess checks if user has access to a specific tenant.
type Generator ¶
type Generator struct {
// contains filtered or unexported fields
}
Generator handles JWT token generation and validation.
func NewGenerator ¶
func NewGenerator(config TokenConfig) *Generator
NewGenerator creates a new token generator.
func (*Generator) GenerateAccessToken ¶
GenerateAccessToken creates a new access token.
func (*Generator) GenerateAccessTokenWithTenant ¶
func (g *Generator) GenerateAccessTokenWithTenant(userID, email, sessionID string, tenant TenantContext) (string, time.Time, error)
GenerateAccessTokenWithTenant creates an access token with tenant context.
func (*Generator) GenerateGlobalRefreshToken ¶
func (g *Generator) GenerateGlobalRefreshToken(userID, email, name, sessionID string) (string, time.Time, error)
GenerateGlobalRefreshToken creates a refresh token without any tenant context. This is used for the new "global refresh + tenant-scoped access" flow. The refresh token only contains user identity, no tenant information.
func (*Generator) GenerateJobToken ¶
func (g *Generator) GenerateJobToken( agentID, jobID, tenantID, jobType string, ttl time.Duration, scopes []JobTokenScope, ) (*JobToken, error)
GenerateJobToken creates a new job token for platform agent job operations. This implements SEC-C03: JWT job auth tokens with scopes.
Security properties: - Short TTL (job timeout + buffer) to minimize exposure window - Scoped to specific job, agent, and tenant - Cannot be used for any other purpose than job operations - Verified in addition to API key (defense-in-depth)
func (*Generator) GenerateRefreshToken ¶
GenerateRefreshToken creates a new refresh token.
func (*Generator) GenerateShortLivedToken ¶
func (g *Generator) GenerateShortLivedToken(userID, tenantID string, ttl time.Duration) (string, error)
GenerateShortLivedToken creates a short-lived token for WebSocket authentication. This is used when WebSocket connections cannot use httpOnly cookies due to cross-origin restrictions (e.g., frontend on port 3000, backend on port 8080). The token is passed as a query parameter during WebSocket handshake.
func (*Generator) GenerateSlimAccessToken ¶
func (g *Generator) GenerateSlimAccessToken( userID, email, name, sessionID string, tenant TenantMembership, permVersion int, ) (*SlimAccessToken, error)
GenerateSlimAccessToken creates an access token WITHOUT embedded permissions. This is the preferred method for the real-time permission sync system.
Instead of embedding permissions in JWT (which can exceed 4KB cookie limit), this method only includes the permission version number. The frontend: 1. Stores permissions in localStorage 2. Checks version on each API response (X-Permission-Stale header) 3. Refreshes permissions when version mismatch detected
Benefits: - JWT size is always ~400 bytes (fixed, regardless of permission count) - Permissions update in real-time when admin changes roles - No browser cookie limit issues
func (*Generator) GenerateTenantScopedAccessToken ¶
func (g *Generator) GenerateTenantScopedAccessToken(userID, email, name, sessionID string, tenant TenantMembership, isAdmin bool) (*TenantScopedAccessToken, error)
GenerateTenantScopedAccessToken creates an access token scoped to a specific tenant. This token contains only the user's role for the specified tenant.
Permission handling: - Owner/Admin (isAdmin=true): No permissions in JWT, bypass all permission checks - Member/Viewer/Custom (isAdmin=false): Permissions derived from role and included in JWT
JWT size is kept under 4KB browser cookie limit: - Owner/Admin: ~500 bytes (no permissions) - Member: ~1.5KB (~42 permissions) - Viewer: ~1KB (~25 permissions)
func (*Generator) GenerateTenantScopedAccessTokenWithPermissions ¶
func (g *Generator) GenerateTenantScopedAccessTokenWithPermissions(userID, email, name, sessionID string, tenant TenantMembership, permissions []string, roles []string, isAdmin bool) (*TenantScopedAccessToken, error)
GenerateTenantScopedAccessTokenWithPermissions creates an access token with explicit permissions. This is used when permissions come from the database (multiple roles system) rather than hardcoded role mappings. roles parameter contains the role names (e.g., "owner", "admin", "custom_role") for display purposes.
Permission handling: - Owner/Admin (isAdmin=true): No permissions in JWT, bypass all permission checks - Member/Viewer/Custom (isAdmin=false): Permissions from database included in JWT
Note: For custom RBAC roles with many permissions, JWT might exceed 4KB. In that case, consider limiting permissions or using role-based bypass.
func (*Generator) GenerateTokenPair ¶
GenerateTokenPair creates both access and refresh tokens.
func (*Generator) GenerateTokenPairWithMemberships ¶
func (g *Generator) GenerateTokenPairWithMemberships(userID, email, name, sessionID string, tenants []TenantMembership, isAdmin bool) (*TokenPair, error)
GenerateTokenPairWithMemberships creates both access and refresh tokens with all tenant memberships. This is the preferred method for multi-tenant authorization.
func (*Generator) GenerateTokenPairWithTenant ¶
func (g *Generator) GenerateTokenPairWithTenant(userID, email, sessionID string, tenant TenantContext) (*TokenPair, error)
GenerateTokenPairWithTenant creates both access and refresh tokens with tenant context.
func (*Generator) ValidateAccessToken ¶
ValidateAccessToken validates an access token specifically.
func (*Generator) ValidateJobToken ¶
func (g *Generator) ValidateJobToken(tokenString string) (*JobTokenClaims, error)
ValidateJobToken validates a job token and returns its claims. Use this to verify job tokens in API handlers.
func (*Generator) ValidateJobTokenForJob ¶
func (g *Generator) ValidateJobTokenForJob(tokenString, expectedAgentID, expectedJobID string) (*JobTokenClaims, error)
ValidateJobTokenForJob validates a job token for a specific job and agent. This is the recommended validation method as it ensures the token is for the right context.
func (*Generator) ValidateJobTokenWithScope ¶
func (g *Generator) ValidateJobTokenWithScope(tokenString string, requiredScope JobTokenScope) (*JobTokenClaims, error)
ValidateJobTokenWithScope validates a job token and checks for a required scope.
func (*Generator) ValidateRefreshToken ¶
ValidateRefreshToken validates a refresh token specifically.
type GlobalRefreshTokenResult ¶
type GlobalRefreshTokenResult struct {
RefreshToken string
ExpiresAt time.Time
Tenants []TenantMembership
}
GlobalRefreshTokenResult contains a global refresh token with user's tenant memberships.
type JobToken ¶
type JobToken struct {
Token string
AgentID string
JobID string
TenantID string
Scopes []JobTokenScope
ExpiresAt time.Time
}
JobToken represents a generated job token with metadata.
type JobTokenClaims ¶
type JobTokenClaims struct {
TokenType TokenType `json:"token_type"`
AgentID string `json:"agent_id"` // Platform agent ID
JobID string `json:"job_id"` // Command/Job ID
TenantID string `json:"tenant_id"` // Tenant owning the job
Scopes []JobTokenScope `json:"scopes"` // Allowed operations
JobType string `json:"job_type,omitempty"` // scan, collect, etc.
jwt.RegisteredClaims
}
JobTokenClaims represents claims specific to job tokens. These are more restrictive than user tokens - tied to a specific job and agent.
func (*JobTokenClaims) HasAnyScope ¶
func (c *JobTokenClaims) HasAnyScope(scopes ...JobTokenScope) bool
HasAnyScope checks if the token has any of the specified scopes.
func (*JobTokenClaims) HasScope ¶
func (c *JobTokenClaims) HasScope(scope JobTokenScope) bool
HasScope checks if the token has a specific scope.
type JobTokenScope ¶
type JobTokenScope string
JobTokenScope represents allowed operations for a job token.
const ( // JobScopeUpdateStatus allows updating job status (running, progress). JobScopeUpdateStatus JobTokenScope = "job:status" // JobScopeReportResult allows reporting job results. JobScopeReportResult JobTokenScope = "job:result" // JobScopeIngestFindings allows ingesting scan findings. JobScopeIngestFindings JobTokenScope = "job:ingest" )
func AllJobScopes ¶
func AllJobScopes() []JobTokenScope
AllJobScopes returns all available job scopes.
type SlimAccessToken ¶
type SlimAccessToken struct {
AccessToken string
TenantID string
TenantSlug string
Role string
PermVersion int
ExpiresAt time.Time
}
SlimAccessToken contains an access token without embedded permissions. Used with the real-time permission sync system.
type TenantContext ¶
TenantContext holds tenant-specific context for token generation.
type TenantMembership ¶
type TenantMembership struct {
TenantID string `json:"tenant_id"`
TenantSlug string `json:"tenant_slug,omitempty"`
Role string `json:"role"` // owner, admin, member, viewer
}
TenantMembership represents a user's membership in a tenant.
type TenantScopedAccessToken ¶
type TenantScopedAccessToken struct {
AccessToken string
TenantID string
TenantSlug string
Role string
ExpiresAt time.Time
}
TenantScopedAccessToken contains an access token scoped to a specific tenant.
type TokenConfig ¶
type TokenConfig struct {
Secret string
Issuer string
AccessTokenDuration time.Duration
RefreshTokenDuration time.Duration
}
TokenConfig holds configuration for token generation.