authorizer/server/resolvers/validate_jwt_token.go

95 lines
2.7 KiB
Go
Raw Normal View History

package resolvers
import (
"context"
"errors"
"fmt"
"strings"
2022-05-24 07:12:29 +00:00
"github.com/golang-jwt/jwt"
log "github.com/sirupsen/logrus"
"github.com/authorizerdev/authorizer/server/graph/model"
2022-05-27 17:50:38 +00:00
"github.com/authorizerdev/authorizer/server/memorystore"
2022-05-30 06:24:16 +00:00
"github.com/authorizerdev/authorizer/server/parsers"
"github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils"
)
// ValidateJwtTokenResolver is used to validate a jwt token without its rotation
// this can be used at API level (backend)
// it can validate:
// access_token
// id_token
// refresh_token
func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) {
gc, err := utils.GinContextFromContext(ctx)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Failed to get GinContext: ", err)
return nil, err
}
tokenType := params.TokenType
if tokenType != "access_token" && tokenType != "refresh_token" && tokenType != "id_token" {
2022-05-25 07:00:22 +00:00
log.Debug("Invalid token type: ", tokenType)
return nil, errors.New("invalid token type")
}
userID := ""
nonce := ""
// access_token and refresh_token should be validated from session store as well
if tokenType == "access_token" || tokenType == "refresh_token" {
2022-05-29 11:52:46 +00:00
savedSession, err := memorystore.Provider.GetState(params.Token)
if savedSession == "" || err != nil {
return &model.ValidateJWTTokenResponse{
IsValid: false,
}, nil
}
savedSessionSplit := strings.Split(savedSession, "@")
nonce = savedSessionSplit[0]
userID = savedSessionSplit[1]
}
2022-05-30 06:24:16 +00:00
hostname := parsers.GetHost(gc)
var claimRoles []string
var claims jwt.MapClaims
// we cannot validate sub and nonce in case of id_token as that token is not persisted in session store
if userID != "" && nonce != "" {
claims, err = token.ParseJWTToken(params.Token, hostname, nonce, userID)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Failed to parse jwt token: ", err)
return &model.ValidateJWTTokenResponse{
IsValid: false,
}, nil
}
} else {
claims, err = token.ParseJWTTokenWithoutNonce(params.Token, hostname)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Failed to parse jwt token without nonce: ", err)
return &model.ValidateJWTTokenResponse{
IsValid: false,
}, nil
}
}
claimRolesInterface := claims["roles"]
roleSlice := utils.ConvertInterfaceToSlice(claimRolesInterface)
for _, v := range roleSlice {
claimRoles = append(claimRoles, v.(string))
}
if params.Roles != nil && len(params.Roles) > 0 {
for _, v := range params.Roles {
if !utils.StringSliceContains(claimRoles, v) {
2022-05-25 07:00:22 +00:00
log.Debug("Token does not have required role: ", v)
return nil, fmt.Errorf(`unauthorized`)
}
}
}
return &model.ValidateJWTTokenResponse{
IsValid: true,
}, nil
}