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