jwt

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Feb 12, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package jwt provides JWT token generation and validation utilities.

Index

Constants

This section is empty.

Variables

View Source
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

func GenerateToken(userID, role, secret string, expiry time.Duration) (string, error)

GenerateToken creates a new JWT token with the given claims (legacy support).

func GenerateTokenWithExpiry

func GenerateTokenWithExpiry(userID, role, secret string, expiresAt time.Time) (string, error)

GenerateTokenWithExpiry creates a token that expires at a specific time.

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

func ValidateToken(tokenString, secret string) (*Claims, error)

ValidateToken validates the token and returns the claims.

func (*Claims) GetAccessibleTenantIDs

func (c *Claims) GetAccessibleTenantIDs() []string

GetAccessibleTenantIDs returns all tenant IDs the user has access to.

func (*Claims) GetTenantRole

func (c *Claims) GetTenantRole(tenantID string) string

GetTenantRole returns the user's role in a specific tenant.

func (*Claims) HasAllPermissions

func (c *Claims) HasAllPermissions(permissions ...string) bool

HasAllPermissions checks if the claims include all specified permissions.

func (*Claims) HasAnyPermission

func (c *Claims) HasAnyPermission(permissions ...string) bool

HasAnyPermission checks if the claims include any of the specified permissions.

func (*Claims) HasPermission

func (c *Claims) HasPermission(permission string) bool

HasPermission checks if the claims include a specific permission.

func (*Claims) HasTenantAccess

func (c *Claims) HasTenantAccess(tenantID string) bool

HasTenantAccess checks if user has access to a specific tenant.

func (*Claims) HasTenantRole

func (c *Claims) HasTenantRole(tenantID string, requiredRole string) bool

HasTenantRole checks if user has a specific role (or higher) in a tenant. Role hierarchy: owner > admin > member > viewer

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

func (g *Generator) GenerateAccessToken(userID, sessionID, role string) (string, time.Time, error)

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

func (g *Generator) GenerateRefreshToken(userID, sessionID string) (string, time.Time, error)

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

func (g *Generator) GenerateTokenPair(userID, sessionID, role string) (*TokenPair, error)

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

func (g *Generator) ValidateAccessToken(tokenString string) (*Claims, error)

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

func (g *Generator) ValidateRefreshToken(tokenString string) (*Claims, error)

ValidateRefreshToken validates a refresh token specifically.

func (*Generator) ValidateToken

func (g *Generator) ValidateToken(tokenString string) (*Claims, error)

ValidateToken validates the token and returns the claims.

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

type TenantContext struct {
	TenantID    string
	Role        string
	Permissions []string
	IsAdmin     bool
}

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.

type TokenPair

type TokenPair struct {
	AccessToken  string
	RefreshToken string
	ExpiresAt    time.Time
}

TokenPair contains both access and refresh tokens.

type TokenType

type TokenType string

TokenType represents the type of JWT token.

const (
	// TokenTypeAccess is a short-lived access token.
	TokenTypeAccess TokenType = "access"
	// TokenTypeRefresh is a long-lived refresh token.
	TokenTypeRefresh TokenType = "refresh"
	// TokenTypeJob is a job-specific token for platform agents.
	TokenTypeJob TokenType = "job"
)

Jump to

Keyboard shortcuts

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