feat: add token IDs, store tokens in db for early invalidation
This commit is contained in:
parent
58c1c1794e
commit
e5723360a7
7 changed files with 248 additions and 9 deletions
|
@ -5,6 +5,7 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"codeberg.org/u1f320/pronouns.cc/backend/log"
|
||||
"codeberg.org/u1f320/pronouns.cc/backend/server/auth"
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
@ -28,6 +29,27 @@ func (s *Server) maybeAuth(next http.Handler) http.Handler {
|
|||
return
|
||||
}
|
||||
|
||||
// "valid" here refers to existence and expiry date, not whether the token is known
|
||||
valid, err := s.DB.TokenValid(r.Context(), claims.UserID, claims.TokenID)
|
||||
if err != nil {
|
||||
log.Errorf("validating token for user %v: %v", claims.UserID, err)
|
||||
render.Status(r, errCodeStatuses[ErrInternalServerError])
|
||||
render.JSON(w, r, APIError{
|
||||
Code: ErrInternalServerError,
|
||||
Message: errCodeMessages[ErrInternalServerError],
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if !valid {
|
||||
render.Status(r, errCodeStatuses[ErrInvalidToken])
|
||||
render.JSON(w, r, APIError{
|
||||
Code: ErrInvalidToken,
|
||||
Message: errCodeMessages[ErrInvalidToken],
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), ctxKeyClaims, claims)
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
|
|
|
@ -14,7 +14,13 @@ import (
|
|||
|
||||
// Claims are the claims used in a token.
|
||||
type Claims struct {
|
||||
UserID xid.ID `json:"sub"`
|
||||
UserID xid.ID `json:"sub"`
|
||||
TokenID xid.ID `json:"jti"`
|
||||
UserIsAdmin bool `json:"adm"`
|
||||
|
||||
// TokenWrite specifies whether this token can be used for write actions.
|
||||
// If set to false, this token can only be used for read actions.
|
||||
TokenWrite bool `json:"twr"`
|
||||
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
@ -37,16 +43,20 @@ func New() *Verifier {
|
|||
return &Verifier{key: key}
|
||||
}
|
||||
|
||||
const expireDays = 30
|
||||
// ExpireDays is after how many days the token will expire.
|
||||
const ExpireDays = 30
|
||||
|
||||
// CreateToken creates a token for the given user ID.
|
||||
// It expires after 30 days.
|
||||
func (v *Verifier) CreateToken(userID xid.ID) (string, error) {
|
||||
func (v *Verifier) CreateToken(userID, tokenID xid.ID, isAdmin bool, isWriteToken bool) (token string, err error) {
|
||||
now := time.Now()
|
||||
expires := now.Add(expireDays * 24 * time.Hour)
|
||||
expires := now.Add(ExpireDays * 24 * time.Hour)
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{
|
||||
UserID: userID,
|
||||
t := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{
|
||||
UserID: userID,
|
||||
TokenID: tokenID,
|
||||
UserIsAdmin: isAdmin,
|
||||
TokenWrite: isWriteToken,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Issuer: "pronouns",
|
||||
ExpiresAt: jwt.NewNumericDate(expires),
|
||||
|
@ -55,7 +65,7 @@ func (v *Verifier) CreateToken(userID xid.ID) (string, error) {
|
|||
},
|
||||
})
|
||||
|
||||
return token.SignedString(v.key)
|
||||
return t.SignedString(v.key)
|
||||
}
|
||||
|
||||
// Claims parses the given token and returns its Claims.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue