fix: logout revokes the session under serve: the jwt blacklist and GORM hooks are wired when the database is published

Boot runs before summer serve publishes the database, so the plugin's GORM
hooks, the Postgres jwt_blacklist store and its sweep now go through
lagoon.OnDatabase, and the jwt guard resolves the published store on every
request. A logged-out token is refused on jwt.auth, /fetch and /refresh.

The jwt guard reads the cookie names from classes.SessionCookieNames().
This commit is contained in:
Jakub Zych
2026-10-22 22:29:59 +02:00
parent 8e4b863a3f
commit 4bf44fc6ea
6 changed files with 294 additions and 22 deletions

View File

@@ -70,10 +70,21 @@ func (p *Plugin) Boot(app *backpack.App) error {
if err != nil {
return err
}
if gdb, ok := app.Lookup[*gorm.DB](); ok {
// Serve publishes the database after Boot, so the GORM hooks, the
// blacklist store and its sweep are installed on lagoon.Publish, or at
// once when the database is already published.
if err := lagoon.OnDatabase(app, func(sqlDB *sql.DB, gdb *gorm.DB) error {
if err := classes.RegisterHooks(gdb); err != nil {
return err
}
store := bouncer.NewPostgresBlacklist(sqlDB, "jwt_blacklist")
if err := app.Publish[bouncer.BlacklistStore](store); err != nil {
return err
}
p.startBlacklistSweep(store)
return nil
}); err != nil {
return err
}
reg, ok := app.Lookup[*bouncer.Registry]()
if !ok || reg == nil {
@@ -82,21 +93,7 @@ func (p *Plugin) Boot(app *backpack.App) error {
return err
}
}
var bl bouncer.BlacklistStore
if sqlDB, ok := app.Lookup[*sql.DB](); ok && sqlDB != nil {
bl = bouncer.NewPostgresBlacklist(sqlDB, "jwt_blacklist")
} else if gdb, ok := app.Lookup[*gorm.DB](); ok && gdb != nil {
if sqlDB, err := gdb.DB(); err == nil && sqlDB != nil {
bl = bouncer.NewPostgresBlacklist(sqlDB, "jwt_blacklist")
}
}
if bl != nil {
if err := app.Publish[bouncer.BlacklistStore](bl); err != nil {
return err
}
p.startBlacklistSweep(bl)
}
if err := reg.Register(p.ID(), "jwt", bouncer.NewJWTGuard(secret, classes.GormUsers{App: app}, bl, "token", "auth_token")); err != nil {
if err := reg.Register(p.ID(), "jwt", bouncer.NewJWTGuard(secret, classes.GormUsers{App: app}, &appBlacklist{app: app}, classes.SessionCookieNames()...)); err != nil {
return err
}
prefix, err := classes.APITokenPrefix(app)