adding jwt authentication
This commit is contained in:
@@ -5,12 +5,12 @@ import (
|
|||||||
|
|
||||||
"adam-french.co.uk/backend/models"
|
"adam-french.co.uk/backend/models"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreatePostInput struct {
|
type CreatePostInput struct {
|
||||||
Title string `json:"title" binding:"required"`
|
Title string `json:"title" binding:"required"`
|
||||||
Content string `json:"content" binding:"required"`
|
Content string `json:"content" binding:"required"`
|
||||||
Author string `json:"author" binding:"required"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *Store) GetPosts(ctx *gin.Context) {
|
func (store *Store) GetPosts(ctx *gin.Context) {
|
||||||
@@ -19,7 +19,18 @@ func (store *Store) GetPosts(ctx *gin.Context) {
|
|||||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, gin.H{"data": models.Post{}})
|
ctx.JSON(http.StatusOK, gin.H{"data": posts})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store *Store) GetPost(ctx *gin.Context) {
|
||||||
|
postID := ctx.Param("id")
|
||||||
|
var post models.Post
|
||||||
|
if err := store.DB.First(&post, postID).Error; err != nil {
|
||||||
|
ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, gin.H{"data": post})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *Store) CreatePost(ctx *gin.Context) {
|
func (store *Store) CreatePost(ctx *gin.Context) {
|
||||||
@@ -29,21 +40,61 @@ func (store *Store) CreatePost(ctx *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
claimsVal, ok := ctx.Get("userClaims")
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user claims could not be found"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, ok := claimsVal.(*jwt.MapClaims)
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid claims"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, ok := (*claims)["id"].(uint)
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user id in claims"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Create post
|
// Create post
|
||||||
post := models.Post{Title: input.Title, Content: input.Content, Author: input.Author}
|
post := models.Post{Title: input.Title, Content: input.Content, AuthorID: userID}
|
||||||
store.DB.Create(&post)
|
store.DB.Create(&post)
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, gin.H{"data": post})
|
ctx.JSON(http.StatusCreated, gin.H{"data": post})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *Store) UpdatePost(ctx *gin.Context) {
|
func (store *Store) UpdatePost(ctx *gin.Context) {
|
||||||
id := ctx.Param("id")
|
postID := ctx.Param("id")
|
||||||
var post models.Post
|
var post models.Post
|
||||||
if err := store.DB.First(&post, id).Error; err != nil {
|
if err := store.DB.First(&post, postID).Error; err != nil {
|
||||||
ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
claimsVal, ok := ctx.Get("userClaims")
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user claims could not be found"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, ok := claimsVal.(*jwt.MapClaims)
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid claims"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, ok := (*claims)["id"].(uint)
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user id in claims"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(userID == post.AuthorID) {
|
||||||
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user and post author id missmatch"})
|
||||||
|
}
|
||||||
|
|
||||||
var input CreatePostInput
|
var input CreatePostInput
|
||||||
if err := ctx.ShouldBindBodyWithJSON(&input); err != nil {
|
if err := ctx.ShouldBindBodyWithJSON(&input); err != nil {
|
||||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
@@ -52,8 +103,41 @@ func (store *Store) UpdatePost(ctx *gin.Context) {
|
|||||||
|
|
||||||
post.Title = input.Title
|
post.Title = input.Title
|
||||||
post.Content = input.Content
|
post.Content = input.Content
|
||||||
post.Author = input.Author
|
|
||||||
store.DB.Save(&post)
|
store.DB.Save(&post)
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, gin.H{"data": post})
|
ctx.JSON(http.StatusOK, gin.H{"data": post})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (store *Store) DeletePost(ctx *gin.Context) {
|
||||||
|
postID := ctx.Param("id")
|
||||||
|
var post models.Post
|
||||||
|
if err := store.DB.First(&post, postID).Error; err != nil {
|
||||||
|
ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claimsVal, ok := ctx.Get("userClaims")
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user claims could not be found"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, ok := claimsVal.(*jwt.MapClaims)
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid claims"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, ok := (*claims)["id"].(uint)
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user id in claims"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(userID == post.AuthorID) {
|
||||||
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user and post author id missmatch"})
|
||||||
|
}
|
||||||
|
|
||||||
|
store.DB.Delete(&post)
|
||||||
|
ctx.JSON(http.StatusOK, gin.H{"data": post})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package handlers
|
|
||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
|
||||||
|
|
||||||
func (store *Store) RefreshToken(ctx *gin.Context) {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"adam-french.co.uk/backend/models"
|
"adam-french.co.uk/backend/models"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,35 +31,41 @@ func (store *Store) CreateUser(ctx *gin.Context) {
|
|||||||
store.DB.Create(&user)
|
store.DB.Create(&user)
|
||||||
|
|
||||||
// Generate JWT token
|
// Generate JWT token
|
||||||
|
tokens, err := store.Auth.GenerateJWT(&user)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.SetCookie(
|
||||||
|
"access_token",
|
||||||
|
tokens.AccessToken,
|
||||||
|
int(store.Auth.Config.AccessTokenLifetime.Seconds()),
|
||||||
|
store.Auth.Config.Endpoint,
|
||||||
|
store.Auth.Config.Domain,
|
||||||
|
true, true,
|
||||||
|
)
|
||||||
|
ctx.SetCookie(
|
||||||
|
"refresh_token",
|
||||||
|
tokens.RefreshToken,
|
||||||
|
int(store.Auth.Config.RefreshTokenLifetime.Seconds()),
|
||||||
|
store.Auth.Config.Endpoint,
|
||||||
|
store.Auth.Config.Domain,
|
||||||
|
true, true,
|
||||||
|
)
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, gin.H{"data": user})
|
ctx.JSON(http.StatusOK, gin.H{"data": user})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *Store) LoginUser(ctx *gin.Context) {
|
func (store *Store) GetUser(ctx *gin.Context) {
|
||||||
var input UserCredentials
|
userID := ctx.Param("id")
|
||||||
if err := ctx.ShouldBindBodyWithJSON(&input); err != nil {
|
var user models.User
|
||||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
if err := store.DB.First(&user, userID).Error; err != nil {
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
user := models.User{Username: input.Username}
|
|
||||||
if err := store.DB.Where("username = ?", input.Username).First(&user).Error; err != nil {
|
|
||||||
ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(input.Password)); err != nil {
|
ctx.JSON(http.StatusOK, gin.H{"data": user})
|
||||||
ctx.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate JWT token
|
|
||||||
|
|
||||||
ctx.JSON(http.StatusAccepted, gin.H{"data": user})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (store *Store) GetUser(ctx *gin.Context) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *Store) GetUsers(ctx *gin.Context) {
|
func (store *Store) GetUsers(ctx *gin.Context) {
|
||||||
@@ -67,9 +74,63 @@ func (store *Store) GetUsers(ctx *gin.Context) {
|
|||||||
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, gin.H{"data": models.Post{}})
|
ctx.JSON(http.StatusOK, gin.H{"data": users})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *Store) UpdateUser(c *gin.Context) {
|
func (store *Store) UpdateUser(ctx *gin.Context) {
|
||||||
|
claimsVal, ok := ctx.Get("userClaims")
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user claims could not be found"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, ok := claimsVal.(*jwt.MapClaims)
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid claims"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, ok := (*claims)["id"].(uint)
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user id in claims"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := store.DB.First(&user, userID).Error; err != nil {
|
||||||
|
ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "will be implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store *Store) DeleteUser(ctx *gin.Context) {
|
||||||
|
claimsVal, ok := ctx.Get("userClaims")
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user claims could not be found"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, ok := claimsVal.(*jwt.MapClaims)
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid claims"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, ok := (*claims)["id"].(uint)
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user id in claims"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := store.DB.First(&user, userID).Error; err != nil {
|
||||||
|
ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
store.DB.Delete(&user)
|
||||||
|
ctx.JSON(http.StatusOK, gin.H{"data": user})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
@@ -31,25 +32,34 @@ func main() {
|
|||||||
spotifyAuth, client := services.InitSpotifyAuth(&spotifyConfig)
|
spotifyAuth, client := services.InitSpotifyAuth(&spotifyConfig)
|
||||||
|
|
||||||
authSecret := os.Getenv("BACKEND_SECRET")
|
authSecret := os.Getenv("BACKEND_SECRET")
|
||||||
authConfig := services.AuthConfig{Secret: []byte(authSecret)}
|
domainName := os.Getenv("DOMAIN")
|
||||||
|
backendEndpoint := os.Getenv("BACKEND_ENDPOINT")
|
||||||
|
accessTokenLifetime := 24 * time.Hour
|
||||||
|
refreshTokenLifetime := 365 * 24 * time.Hour
|
||||||
|
authConfig := services.AuthConfig{Secret: []byte(authSecret), Domain: domainName, RefreshTokenLifetime: refreshTokenLifetime, AccessTokenLifetime: accessTokenLifetime, Endpoint: backendEndpoint}
|
||||||
auth := services.InitAuth(&authConfig)
|
auth := services.InitAuth(&authConfig)
|
||||||
|
|
||||||
store := handlers.Store{DB: db, SpotifyAuth: spotifyAuth, SpotifyClient: client, Auth: auth}
|
store := handlers.Store{DB: db, SpotifyAuth: spotifyAuth, SpotifyClient: client, Auth: auth}
|
||||||
|
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
protected := r.Group("/", store.AuthMiddlewear)
|
||||||
|
|
||||||
r.GET("/posts", store.GetPosts)
|
r.GET("/posts", store.GetPosts)
|
||||||
r.POST("/posts", store.CreatePost)
|
protected.POST("/posts", store.CreatePost)
|
||||||
r.PUT("/posts/:id", store.UpdatePost)
|
r.GET("/posts/:id", store.GetPost)
|
||||||
|
protected.PUT("/posts/:id", store.UpdatePost)
|
||||||
|
protected.DELETE("/posts/:id", store.DeletePost)
|
||||||
|
|
||||||
r.GET("/user/:id", store.GetUser)
|
r.GET("/user/:id", store.GetUser)
|
||||||
|
protected.PUT("/user/:id", store.UpdateUser)
|
||||||
|
protected.DELETE("/user/:id", store.DeleteUser)
|
||||||
r.GET("/user", store.GetUsers)
|
r.GET("/user", store.GetUsers)
|
||||||
r.POST("/user", store.CreateUser)
|
r.POST("/user", store.CreateUser)
|
||||||
r.PUT("/user", store.UpdateUser)
|
|
||||||
|
|
||||||
r.POST("/refresh", store.RefreshToken)
|
r.POST("/auth/login", store.Login)
|
||||||
|
r.POST("/auth/refresh", store.RefreshToken)
|
||||||
|
|
||||||
r.GET("/callback", store.CompleteSpotifyAuth)
|
r.GET("/spotify/callback", store.CompleteSpotifyAuth)
|
||||||
r.GET("/spotify/listening", store.ListeningTo)
|
r.GET("/spotify/listening", store.ListeningTo)
|
||||||
r.GET("/spotify/recent", store.RecentlyPlayed)
|
r.GET("/spotify/recent", store.RecentlyPlayed)
|
||||||
// r.POST("/spotify", store.SendSong)
|
// r.POST("/spotify", store.SendSong)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import "gorm.io/gorm"
|
|||||||
type Post struct {
|
type Post struct {
|
||||||
gorm.Model // includes ID, CreatedAt, UpdatedAt, DeletedAt
|
gorm.Model // includes ID, CreatedAt, UpdatedAt, DeletedAt
|
||||||
Title string `gorm:"not null"`
|
Title string `gorm:"not null"`
|
||||||
Content string `gorm:"type:text; not null"`
|
AuthorID uint
|
||||||
Author string `gorm:"not null"`
|
Author User `gorm:"foreignKey:AuthorID"`
|
||||||
|
Content string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"adam-french.co.uk/backend/models"
|
"adam-french.co.uk/backend/models"
|
||||||
@@ -8,11 +9,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Auth struct {
|
type Auth struct {
|
||||||
config *AuthConfig
|
Config *AuthConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthConfig struct {
|
type AuthConfig struct {
|
||||||
Secret []byte
|
Secret []byte
|
||||||
|
Domain string
|
||||||
|
AccessTokenLifetime time.Duration
|
||||||
|
RefreshTokenLifetime time.Duration
|
||||||
|
Endpoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tokens struct {
|
type Tokens struct {
|
||||||
@@ -21,7 +26,7 @@ type Tokens struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func InitAuth(config *AuthConfig) *Auth {
|
func InitAuth(config *AuthConfig) *Auth {
|
||||||
auth := Auth{config: config}
|
auth := Auth{Config: config}
|
||||||
|
|
||||||
return &auth
|
return &auth
|
||||||
}
|
}
|
||||||
@@ -31,20 +36,20 @@ func (auth *Auth) GenerateJWT(user *models.User) (*Tokens, error) {
|
|||||||
"username": user.Username,
|
"username": user.Username,
|
||||||
"id": user.ID,
|
"id": user.ID,
|
||||||
"admin": user.Admin,
|
"admin": user.Admin,
|
||||||
"exp": time.Now().AddDate(0, 0, 1).Unix(),
|
"exp": time.Now().Add(auth.Config.AccessTokenLifetime).Unix(),
|
||||||
})
|
})
|
||||||
|
|
||||||
refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||||
"id": user.ID,
|
"id": user.ID,
|
||||||
"exp": time.Now().AddDate(1, 0, 0).Unix(),
|
"exp": time.Now().Add(auth.Config.RefreshTokenLifetime).Unix(),
|
||||||
})
|
})
|
||||||
|
|
||||||
accessTokenString, err := accessToken.SignedString(auth.config.Secret)
|
accessTokenString, err := accessToken.SignedString(auth.Config.Secret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshTokenString, err := refreshToken.SignedString(auth.config.Secret)
|
refreshTokenString, err := refreshToken.SignedString(auth.Config.Secret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -52,17 +57,20 @@ func (auth *Auth) GenerateJWT(user *models.User) (*Tokens, error) {
|
|||||||
return &Tokens{AccessToken: accessTokenString, RefreshToken: refreshTokenString}, nil
|
return &Tokens{AccessToken: accessTokenString, RefreshToken: refreshTokenString}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (auth *Auth) VerifyJWT(tokens Tokens) (*jwt.MapClaims, error) {
|
func (auth *Auth) keyFunc(_ *jwt.Token) (any, error) {
|
||||||
token, err := jwt.Parse(tokens.AccessToken, func(token *jwt.Token) (any, error) {
|
return auth.Config.Secret, nil
|
||||||
return auth.config.Secret, nil
|
}
|
||||||
}, jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}))
|
|
||||||
|
func (auth *Auth) VerifyJWT(tokenStr string) (*jwt.MapClaims, error) {
|
||||||
|
token, err := jwt.Parse(tokenStr, auth.keyFunc, jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
claims, ok := token.Claims.(jwt.MapClaims)
|
||||||
return &claims, nil
|
if !ok {
|
||||||
|
return nil, errors.New("Invalid token claims type")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, err
|
return &claims, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user