// MIT License // // Copyright (c) 2024 vinchent // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. package token import ( "errors" "fmt" "sync" "time" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" ) type Config struct { secretKey string expiryTime time.Duration } type Claims struct { IdentityKey string `json:"identity_key"` jwt.RegisteredClaims } type TokenResp struct { Raw string Identity string Expiry time.Time } var ( once sync.Once config Config ) var ErrMissingHeader = errors.New("Authorization is needed in the header") func Init(secretKey string, expiryTime time.Duration) { once.Do(func() { config.secretKey = secretKey config.expiryTime = expiryTime }) } func Sign(identityKey string) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{ identityKey, jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(config.expiryTime)), IssuedAt: jwt.NewNumericDate(time.Now()), NotBefore: jwt.NewNumericDate(time.Now()), }, }) return token.SignedString([]byte(config.secretKey)) } func Parse(tokenString string) (*TokenResp, error) { token, err := jwt.ParseWithClaims( tokenString, &Claims{}, func(t *jwt.Token) (interface{}, error) { if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { return nil, jwt.ErrSignatureInvalid } return []byte(config.secretKey), nil }, ) if err != nil { return nil, err } if claims, ok := token.Claims.(*Claims); ok { return &TokenResp{ tokenString, claims.IdentityKey, claims.ExpiresAt.Time, }, nil } return nil, nil } func ParseRequest(c *gin.Context) (*TokenResp, error) { // NOTE: Authorization: Bearer sdkfjlsfjlskdfjlsjdflk...slkdfjlka header := c.GetHeader("Authorization") if len(header) == 0 { return nil, ErrMissingHeader } // get the token var t string fmt.Sscanf(header, "Bearer %s", &t) return Parse(t) }