Update JWT documentation with correct API usage

- Updated all examples to use jwt.NewDBConnection() wrapper
- Fixed transaction handling to use gen.dbConn.BeginTx()
- Removed references to obsolete jwt.NewSQLExecutor()
- Added missing context imports
- Fixed variable naming in complete example
- Corrected DBConn type from *sql.DB to DBConnection interface

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 16:54:58 +11:00
parent f1799917d8
commit 282b1f3d74

85
JWT.md

@@ -47,7 +47,7 @@ func main() {
FreshExpireAfter: 5, // Tokens stay fresh for 5 minutes FreshExpireAfter: 5, // Tokens stay fresh for 5 minutes
TrustedHost: "example.com", TrustedHost: "example.com",
SecretKey: "your-secret-key-here", SecretKey: "your-secret-key-here",
DBConn: db, DBConn: jwt.NewDBConnection(db),
DBType: jwt.DatabaseType{ DBType: jwt.DatabaseType{
Type: jwt.DatabasePostgreSQL, Type: jwt.DatabasePostgreSQL,
Version: "15", Version: "15",
@@ -59,6 +59,7 @@ func main() {
} }
// Generate tokens // Generate tokens
userID := 42
accessToken, accessExp, err := gen.NewAccess(userID, true, false) accessToken, accessExp, err := gen.NewAccess(userID, true, false)
refreshToken, refreshExp, err := gen.NewRefresh(userID, false) refreshToken, refreshExp, err := gen.NewRefresh(userID, false)
} }
@@ -91,7 +92,7 @@ type GeneratorConfig struct {
SecretKey string // Secret key for token signing SecretKey string // Secret key for token signing
// Optional fields (for database support) // Optional fields (for database support)
DBConn *sql.DB // Database connection (nil to disable revocation) DBConn DBConnection // Database connection (nil to disable revocation)
DBType DatabaseType // Database type and version DBType DatabaseType // Database type and version
TableConfig TableConfig // Table configuration TableConfig TableConfig // Table configuration
} }
@@ -161,24 +162,23 @@ token, expiry, err := gen.NewRefresh(42, true)
Tokens must be validated within a transaction context: Tokens must be validated within a transaction context:
```go ```go
import "context"
// Begin transaction // Begin transaction
tx, err := db.Begin() tx, err := gen.dbConn.BeginTx(context.Background(), nil)
if err != nil { if err != nil {
return err return err
} }
defer tx.Rollback() defer tx.Rollback()
// Create executor
exec := jwt.NewSQLExecutor(tx)
// Validate access token // Validate access token
token, err := gen.ValidateAccess(exec, tokenString) token, err := gen.ValidateAccess(tx, tokenString)
if err != nil { if err != nil {
return err // Token invalid or revoked return err // Token invalid or revoked
} }
// Validate refresh token // Validate refresh token
token, err := gen.ValidateRefresh(exec, tokenString) refreshToken, err := gen.ValidateRefresh(tx, tokenString)
if err != nil { if err != nil {
return err // Token invalid or revoked return err // Token invalid or revoked
} }
@@ -209,19 +209,19 @@ ttl := token.TTL // "session" or "exp"
### Revoking a Token ### Revoking a Token
```go ```go
tx, _ := db.Begin() import "context"
tx, _ := gen.dbConn.BeginTx(context.Background(), nil)
defer tx.Rollback() defer tx.Rollback()
exec := jwt.NewSQLExecutor(tx)
// Validate token first // Validate token first
token, err := gen.ValidateAccess(exec, tokenString) token, err := gen.ValidateAccess(tx, tokenString)
if err != nil { if err != nil {
return err return err
} }
// Revoke the token // Revoke the token
err = token.Revoke(exec) err = token.Revoke(tx)
if err != nil { if err != nil {
return err return err
} }
@@ -232,7 +232,7 @@ tx.Commit()
### Checking Revocation Status ### Checking Revocation Status
```go ```go
isValid, err := token.CheckNotRevoked(exec) isValid, err := token.CheckNotRevoked(tx)
if !isValid { if !isValid {
// Token has been revoked // Token has been revoked
} }
@@ -247,12 +247,17 @@ Tokens can be marked as "fresh" for sensitive operations:
accessToken, _, _ := gen.NewAccess(userID, true, false) // fresh=true accessToken, _, _ := gen.NewAccess(userID, true, false) // fresh=true
// Check freshness // Check freshness
token, _ := gen.ValidateAccess(exec, accessToken) tx, _ := gen.dbConn.BeginTx(context.Background(), nil)
defer tx.Rollback()
token, _ := gen.ValidateAccess(tx, accessToken)
currentTime := time.Now().Unix() currentTime := time.Now().Unix()
if currentTime > token.Fresh { if currentTime > token.Fresh {
// Token is stale, require re-authentication // Token is stale, require re-authentication
return errors.New("token is not fresh") return errors.New("token is not fresh")
} }
tx.Commit()
``` ```
## Cleanup ## Cleanup
@@ -358,7 +363,10 @@ CREATE INDEX IF NOT EXISTS idx_jwtblacklist_sub ON jwtblacklist(sub);
### GORM ### GORM
```go ```go
import "gorm.io/gorm" import (
"context"
"gorm.io/gorm"
)
// Get underlying *sql.DB from GORM // Get underlying *sql.DB from GORM
gormDB, _ := gorm.Open(postgres.Open(dsn), &gorm.Config{}) gormDB, _ := gorm.Open(postgres.Open(dsn), &gorm.Config{})
@@ -367,21 +375,25 @@ sqlDB, _ := gormDB.DB()
// Create generator with sql.DB // Create generator with sql.DB
gen, _ := jwt.CreateGenerator(jwt.GeneratorConfig{ gen, _ := jwt.CreateGenerator(jwt.GeneratorConfig{
// ... config // ... config
DBConn: sqlDB, DBConn: jwt.NewDBConnection(sqlDB),
}) })
// Use with transactions // Use with transactions
tx := gormDB.Begin() tx, _ := gen.dbConn.BeginTx(context.Background(), nil)
sqlTx, _ := tx.DB() defer tx.Rollback()
exec := jwt.NewSQLExecutor(sqlTx)
token, _ := gen.ValidateAccess(exec, tokenString) token, _ := gen.ValidateAccess(tx, tokenString)
tx.Commit() tx.Commit()
``` ```
### Bun ### Bun
```go ```go
import "github.com/uptrace/bun" import (
"context"
"github.com/uptrace/bun"
)
// Get underlying *sql.DB from Bun // Get underlying *sql.DB from Bun
bunDB := bun.NewDB(sqldb, pgdialect.New()) bunDB := bun.NewDB(sqldb, pgdialect.New())
@@ -390,14 +402,15 @@ sqlDB := bunDB.DB // Already *sql.DB
// Create generator // Create generator
gen, _ := jwt.CreateGenerator(jwt.GeneratorConfig{ gen, _ := jwt.CreateGenerator(jwt.GeneratorConfig{
// ... config // ... config
DBConn: sqlDB, DBConn: jwt.NewDBConnection(sqlDB),
}) })
// Use with transactions // Use with transactions
tx, _ := bunDB.Begin() tx, _ := gen.dbConn.BeginTx(context.Background(), nil)
sqlTx, _ := tx.DB() defer tx.Rollback()
exec := jwt.NewSQLExecutor(sqlTx)
token, _ := gen.ValidateAccess(exec, tokenString) token, _ := gen.ValidateAccess(tx, tokenString)
tx.Commit() tx.Commit()
``` ```
@@ -431,7 +444,7 @@ func main() {
FreshExpireAfter: 5, FreshExpireAfter: 5,
TrustedHost: "example.com", TrustedHost: "example.com",
SecretKey: "super-secret-key", SecretKey: "super-secret-key",
DBConn: db, DBConn: jwt.NewDBConnection(db),
DBType: jwt.DatabaseType{ DBType: jwt.DatabaseType{
Type: jwt.DatabasePostgreSQL, Type: jwt.DatabasePostgreSQL,
Version: "15", Version: "15",
@@ -457,10 +470,10 @@ func main() {
fmt.Printf("Refresh Token: %s (expires: %d)\n", refreshToken, refreshExp) fmt.Printf("Refresh Token: %s (expires: %d)\n", refreshToken, refreshExp)
// Validate access token // Validate access token
tx, _ := db.Begin() tx, _ := gen.dbConn.BeginTx(context.Background(), nil)
exec := jwt.NewSQLExecutor(tx) defer tx.Rollback()
token, err := gen.ValidateAccess(exec, accessToken) token, err := gen.ValidateAccess(tx, accessToken)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -468,7 +481,7 @@ func main() {
fmt.Printf("Token valid for user: %d\n", token.SUB) fmt.Printf("Token valid for user: %d\n", token.SUB)
// Revoke token // Revoke token
err = token.Revoke(exec) err = token.Revoke(tx)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -476,15 +489,15 @@ func main() {
tx.Commit() tx.Commit()
// Try to validate revoked token // Try to validate revoked token
tx, _ = db.Begin() tx2, _ := gen.dbConn.BeginTx(context.Background(), nil)
exec = jwt.NewSQLExecutor(tx) defer tx2.Rollback()
_, err = gen.ValidateAccess(exec, accessToken) _, err = gen.ValidateAccess(tx2, accessToken)
if err != nil { if err != nil {
fmt.Println("Token is revoked:", err) fmt.Println("Token is revoked:", err)
} }
tx.Commit() tx2.Commit()
// Cleanup expired tokens // Cleanup expired tokens
err = gen.Cleanup(context.Background()) err = gen.Cleanup(context.Background())