package iam import ( "context" "errors" "time" "github.com/redis/go-redis/v9" ) type tokenCache struct { client *redis.Client } func newTokenCache(addr, password string, db int) (*tokenCache, error) { if addr == "" { return nil, nil } client := redis.NewClient(&redis.Options{Addr: addr, Password: password, DB: db}) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() if err := client.Ping(ctx).Err(); err != nil { return nil, err } return &tokenCache{client: client}, nil } func (c *tokenCache) Close() error { if c == nil || c.client == nil { return nil } return c.client.Close() } func (c *tokenCache) SetSessionActive(ctx context.Context, sid string, ttl time.Duration) error { if c == nil { return nil } return c.client.Set(ctx, "auth:session:"+sid, "active", ttl).Err() } func (c *tokenCache) IsSessionActive(ctx context.Context, sid string) (bool, error) { if c == nil { return false, nil } count, err := c.client.Exists(ctx, "auth:session:"+sid).Result() if err != nil { return false, err } return count == 1, nil } func (c *tokenCache) DeleteSession(ctx context.Context, sid string) error { if c == nil { return nil } return c.client.Del(ctx, "auth:session:"+sid).Err() } func (c *tokenCache) SetRefreshHash(ctx context.Context, rid, tokenHash string, ttl time.Duration) error { if c == nil { return nil } return c.client.Set(ctx, "auth:refresh:"+rid, tokenHash, ttl).Err() } func (c *tokenCache) GetRefreshHash(ctx context.Context, rid string) (string, error) { if c == nil { return "", nil } v, err := c.client.Get(ctx, "auth:refresh:"+rid).Result() if err != nil { if errors.Is(err, redis.Nil) { return "", nil } return "", err } return v, nil } func (c *tokenCache) DeleteRefresh(ctx context.Context, rid string) error { if c == nil { return nil } return c.client.Del(ctx, "auth:refresh:"+rid).Err() } func (c *tokenCache) DenyAccessJTI(ctx context.Context, jti string, ttl time.Duration) error { if c == nil { return nil } return c.client.Set(ctx, "auth:deny:access:"+jti, "1", ttl).Err() } func (c *tokenCache) IsAccessJTIDenied(ctx context.Context, jti string) (bool, error) { if c == nil { return false, nil } count, err := c.client.Exists(ctx, "auth:deny:access:"+jti).Result() if err != nil { return false, err } return count == 1, nil }