151 lines
5.0 KiB
Go
151 lines
5.0 KiB
Go
// Package jwt provides JWT (JSON Web Token) generation and validation with token revocation support.
|
|
//
|
|
// This package implements JWT access and refresh tokens with the ability to revoke tokens
|
|
// using a database-backed blacklist. It supports multiple database backends including
|
|
// PostgreSQL, MySQL, SQLite, and MariaDB, and works with both standard library database/sql
|
|
// and popular ORMs like GORM and Bun.
|
|
//
|
|
// # Features
|
|
//
|
|
// - Access and refresh token generation
|
|
// - Token validation with expiration checking
|
|
// - Token revocation via database blacklist
|
|
// - Support for multiple database types (PostgreSQL, MySQL, SQLite, MariaDB)
|
|
// - Compatible with database/sql, GORM, and Bun ORMs
|
|
// - Automatic table creation and management
|
|
// - Database-native automatic cleanup (PostgreSQL functions, MySQL events)
|
|
// - Manual cleanup method for on-demand token cleanup
|
|
// - Token freshness tracking for sensitive operations
|
|
// - "Remember me" functionality with session vs persistent tokens
|
|
//
|
|
// # Basic Usage
|
|
//
|
|
// Create a token generator with database support:
|
|
//
|
|
// db, _ := sql.Open("postgres", "connection_string")
|
|
// gen, err := jwt.CreateGenerator(jwt.GeneratorConfig{
|
|
// AccessExpireAfter: 15, // 15 minutes
|
|
// RefreshExpireAfter: 1440, // 24 hours
|
|
// FreshExpireAfter: 5, // 5 minutes
|
|
// TrustedHost: "example.com",
|
|
// SecretKey: "your-secret-key",
|
|
// DB: db,
|
|
// DBType: jwt.DatabaseType{Type: jwt.DatabasePostgreSQL, Version: "15"},
|
|
// TableConfig: jwt.DefaultTableConfig(),
|
|
// })
|
|
//
|
|
// Generate tokens:
|
|
//
|
|
// accessToken, accessExp, err := gen.NewAccess(userID, true, false)
|
|
// refreshToken, refreshExp, err := gen.NewRefresh(userID, false)
|
|
//
|
|
// Validate tokens (using standard library):
|
|
//
|
|
// tx, _ := db.Begin()
|
|
// token, err := gen.ValidateAccess(tx, accessToken)
|
|
// if err != nil {
|
|
// // Token is invalid or revoked
|
|
// }
|
|
// tx.Commit()
|
|
//
|
|
// Validate tokens (using ORM like GORM):
|
|
//
|
|
// tx := gormDB.Begin()
|
|
// token, err := gen.ValidateAccess(tx.Statement.ConnPool, accessToken)
|
|
// // or with Bun: gen.ValidateAccess(bunDB.BeginTx(ctx, nil), accessToken)
|
|
// tx.Commit()
|
|
//
|
|
// Revoke tokens:
|
|
//
|
|
// tx, _ := db.Begin()
|
|
// err := token.Revoke(tx)
|
|
// tx.Commit()
|
|
//
|
|
// # Database Configuration
|
|
//
|
|
// The package automatically creates a blacklist table with the following schema:
|
|
//
|
|
// CREATE TABLE jwtblacklist (
|
|
// jti UUID PRIMARY KEY, -- Token unique identifier
|
|
// exp BIGINT NOT NULL, -- Expiration timestamp
|
|
// sub INT NOT NULL, -- Subject (user) ID
|
|
// created_at TIMESTAMP -- When token was blacklisted
|
|
// );
|
|
//
|
|
// # Cleanup
|
|
//
|
|
// For PostgreSQL, the package creates a cleanup function that can be called manually
|
|
// or scheduled with pg_cron:
|
|
//
|
|
// SELECT cleanup_jwtblacklist();
|
|
//
|
|
// For MySQL/MariaDB, the package creates a database event that runs automatically
|
|
// (requires event_scheduler to be enabled).
|
|
//
|
|
// Manual cleanup can be performed at any time:
|
|
//
|
|
// err := gen.Cleanup(context.Background())
|
|
//
|
|
// # Using with ORMs
|
|
//
|
|
// The package works with popular ORMs by using raw SQL queries. For GORM and Bun,
|
|
// wrap the underlying *sql.DB with NewDBConnection() when creating the generator:
|
|
//
|
|
// // GORM example - can use GORM transactions directly
|
|
// gormDB, _ := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
|
// sqlDB, _ := gormDB.DB()
|
|
// gen, _ := jwt.CreateGenerator(jwt.GeneratorConfig{
|
|
// // ... config ...
|
|
// DB: sqlDB,
|
|
// })
|
|
// // Use GORM transaction
|
|
// tx := gormDB.Begin()
|
|
// token, _ := gen.ValidateAccess(tx.Statement.ConnPool, tokenString)
|
|
// tx.Commit()
|
|
//
|
|
// // Bun example - can use Bun transactions directly
|
|
// sqlDB, _ := sql.Open("postgres", dsn)
|
|
// bunDB := bun.NewDB(sqlDB, pgdialect.New())
|
|
// gen, _ := jwt.CreateGenerator(jwt.GeneratorConfig{
|
|
// // ... config ...
|
|
// DB: sqlDB,
|
|
// })
|
|
// // Use Bun transaction
|
|
// tx, _ := bunDB.BeginTx(context.Background(), nil)
|
|
// token, _ := gen.ValidateAccess(tx, tokenString)
|
|
// tx.Commit()
|
|
//
|
|
// # Token Freshness
|
|
//
|
|
// Tokens can be marked as "fresh" for sensitive operations. Fresh tokens are typically
|
|
// required for actions like changing passwords or email addresses:
|
|
//
|
|
// token, err := gen.ValidateAccess(exec, tokenString)
|
|
// if time.Now().Unix() > token.Fresh {
|
|
// // Token is not fresh, require re-authentication
|
|
// }
|
|
//
|
|
// # Custom Table Names
|
|
//
|
|
// You can customize the blacklist table name:
|
|
//
|
|
// config := jwt.DefaultTableConfig()
|
|
// config.TableName = "my_token_blacklist"
|
|
//
|
|
// # Disabling Database Features
|
|
//
|
|
// To use JWT without revocation support (no database):
|
|
//
|
|
// gen, err := jwt.CreateGenerator(jwt.GeneratorConfig{
|
|
// AccessExpireAfter: 15,
|
|
// RefreshExpireAfter: 1440,
|
|
// FreshExpireAfter: 5,
|
|
// TrustedHost: "example.com",
|
|
// SecretKey: "your-secret-key",
|
|
// DB: nil, // No database
|
|
// })
|
|
//
|
|
// When DB is nil, revocation features are disabled and token validation
|
|
// will not check the blacklist.
|
|
package jwt
|