parent
9c06545931
commit
c8697d6ef6
@ -0,0 +1,5 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
const (
|
||||||
|
SESSION_COOKIE = "_owltier.com_sess"
|
||||||
|
)
|
||||||
@ -1,85 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/db"
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/jsend"
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/middleware"
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/token"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Refresh(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
// get user and token from token parse middleware
|
|
||||||
user, err := r.Context().Value(middleware.ContextKeyValues).(*middleware.Values).GetUser()
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t, err := r.Context().Value(middleware.ContextKeyValues).(*middleware.Values).GetRefreshToken()
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if user.Refresh != t {
|
|
||||||
http.Error(w, "Token mismatch", http.StatusUnauthorized)
|
|
||||||
fmt.Printf("%s\n%s", user.Refresh, t)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare login information for the client
|
|
||||||
accessT := token.GenerateAccess(user)
|
|
||||||
refreshT := token.GenerateRefresh(user)
|
|
||||||
db.Update(user, "RefreshToken", refreshT)
|
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: "_owltier.com_auth",
|
|
||||||
Value: accessT,
|
|
||||||
Path: "/",
|
|
||||||
Expires: time.Now().Add(time.Hour),
|
|
||||||
HttpOnly: true,
|
|
||||||
Secure: true,
|
|
||||||
})
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: "_owltier.com_refresh",
|
|
||||||
Value: accessT,
|
|
||||||
Path: "/",
|
|
||||||
Expires: time.Now().Add(time.Hour),
|
|
||||||
HttpOnly: true,
|
|
||||||
Secure: true,
|
|
||||||
})
|
|
||||||
jsend.Success(w, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Validate(w http.ResponseWriter, r *http.Request) {
|
|
||||||
header := r.Header.Get("Authorization")
|
|
||||||
headerVals := strings.Split(header, " ")
|
|
||||||
if strings.ToLower(headerVals[0]) != "bearer" {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
fmt.Fprint(w, "Bad Authorization Scheme")
|
|
||||||
}
|
|
||||||
t := headerVals[1]
|
|
||||||
if t == "" {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
fmt.Fprint(w, "No Token Provided")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
claims, err := token.ValidateAccess(t)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(401)
|
|
||||||
fmt.Fprint(w, "Unauthorized")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if claims.Type != "Access" {
|
|
||||||
w.WriteHeader(401)
|
|
||||||
fmt.Fprint(w, "Unauthorized")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jsend.Success(w, nil)
|
|
||||||
}
|
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package list
|
||||||
|
|
||||||
|
type List struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
CreatedBy string `json:"created_by"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
Breaks []bool `json:"breaks"`
|
||||||
|
NA []string `json:"na"`
|
||||||
|
APAC []string `json:"apac"`
|
||||||
|
Combined []string `json:"combined"`
|
||||||
|
}
|
||||||
@ -1,9 +0,0 @@
|
|||||||
package middleware
|
|
||||||
|
|
||||||
type ContextKey string
|
|
||||||
|
|
||||||
const (
|
|
||||||
ContextKeyUser = ContextKey("user")
|
|
||||||
ContextKeyToken = ContextKey("token")
|
|
||||||
ContextKeyValues = ContextKey("values")
|
|
||||||
)
|
|
||||||
@ -1,138 +0,0 @@
|
|||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/db"
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/token"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Values struct {
|
|
||||||
m map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v Values) GetUser() (*db.UserSchema, error) {
|
|
||||||
u, ok := v.m["user"].(*db.UserSchema)
|
|
||||||
if !ok || u == nil {
|
|
||||||
return nil, errors.New("user is not set")
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
func (v Values) GetAccessToken() (string, error) {
|
|
||||||
u, ok := v.m["access"].(string)
|
|
||||||
if !ok {
|
|
||||||
return "", errors.New("access token is not set")
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
func (v Values) GetRefreshToken() (string, error) {
|
|
||||||
u, ok := v.m["refresh"].(string)
|
|
||||||
if !ok {
|
|
||||||
return "", errors.New("refresh token is not set")
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TokenValidater(next http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
header := r.Header.Get("Authorization")
|
|
||||||
headerVals := strings.Split(header, " ")
|
|
||||||
if strings.ToLower(headerVals[0]) != "bearer" {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
fmt.Fprint(w, "Bad Authorization Scheme")
|
|
||||||
}
|
|
||||||
t := headerVals[1]
|
|
||||||
if t == "" {
|
|
||||||
w.WriteHeader(401)
|
|
||||||
fmt.Fprint(w, "No Token Provided")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
claims, err := token.ValidateAccess(t)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(401)
|
|
||||||
fmt.Fprint(w, "Unauthorized")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if claims.Type != token.TypeAccess {
|
|
||||||
w.WriteHeader(401)
|
|
||||||
fmt.Fprint(w, "Unauthorized")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = &db.UserSchema{}
|
|
||||||
err = db.Fetch(&db.UserSchema{Id: claims.Id}, user)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
w.WriteHeader(400)
|
|
||||||
fmt.Fprint(w, "User Not Found With Id: "+claims.Id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
v := Values{map[string]interface{}{
|
|
||||||
"user": user,
|
|
||||||
"access": t,
|
|
||||||
}}
|
|
||||||
|
|
||||||
ctx := context.WithValue(r.Context(), ContextKeyValues, &v)
|
|
||||||
|
|
||||||
r = r.WithContext(ctx)
|
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func RefreshValidator(next http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
header := r.Header.Get("Authorization")
|
|
||||||
headerVals := strings.Split(header, " ")
|
|
||||||
if strings.ToLower(headerVals[0]) != "bearer" {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
fmt.Fprint(w, "Bad Authorization Scheme")
|
|
||||||
}
|
|
||||||
t := headerVals[1]
|
|
||||||
if t == "" {
|
|
||||||
w.WriteHeader(401)
|
|
||||||
fmt.Fprint(w, "No Token Provided")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
claims, err := token.ValidateRefresh(t)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(401)
|
|
||||||
fmt.Fprint(w, "Unauthorized")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if claims.Type != token.TypeRefresh {
|
|
||||||
w.WriteHeader(401)
|
|
||||||
fmt.Fprint(w, "Unauthorized")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = &db.UserSchema{}
|
|
||||||
err = db.Fetch(&db.UserSchema{Id: claims.Id}, user)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
fmt.Fprint(w, "User Not Found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
v := Values{map[string]interface{}{
|
|
||||||
"user": user,
|
|
||||||
"refresh": t,
|
|
||||||
}}
|
|
||||||
|
|
||||||
ctx := context.WithValue(r.Context(), ContextKeyValues, &v)
|
|
||||||
|
|
||||||
r = r.WithContext(ctx)
|
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
package token
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/config"
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/db"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Claims struct {
|
|
||||||
jwt.RegisteredClaims
|
|
||||||
Id string `json:"id"`
|
|
||||||
Username string `json:"username,omitempty"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
EmailIsVerified bool `json:"email_verified"`
|
|
||||||
XSRF string `json:"xsrf"`
|
|
||||||
Role string `json:"role,omitempty"`
|
|
||||||
Policies []string `json:"policies,omitempty"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Scope string `json:"scope"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func BuildClaims(user *db.UserSchema) *Claims {
|
|
||||||
var c = &Claims{
|
|
||||||
Id: user.Id,
|
|
||||||
Username: user.Username,
|
|
||||||
Email: user.Email,
|
|
||||||
EmailIsVerified: user.EmailIsVerified,
|
|
||||||
XSRF: uuid.New().String(),
|
|
||||||
Scope: user.Scope,
|
|
||||||
Policies: user.Policies,
|
|
||||||
}
|
|
||||||
c.IssuedAt = jwt.NewNumericDate(time.Now())
|
|
||||||
c.NotBefore = jwt.NewNumericDate(time.Now())
|
|
||||||
c.Issuer = config.JwtIssuer()
|
|
||||||
c.Audience = config.JwtAudience()
|
|
||||||
if c.Scope == "" {
|
|
||||||
c.Scope = "default"
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
package token
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/config"
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/db"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ACCESS_EXPIRATION = 10 * time.Minute
|
|
||||||
REFRESH_EXPIRATION = 7 * 24 * time.Hour
|
|
||||||
VERIFY_EMAIL_EXPIRATION = 15 * time.Minute
|
|
||||||
)
|
|
||||||
|
|
||||||
func GenerateAccess(user *db.UserSchema) string {
|
|
||||||
c := BuildClaims(user)
|
|
||||||
c.ExpiresAt = jwt.NewNumericDate(time.Now().Add(ACCESS_EXPIRATION))
|
|
||||||
c.Type = TypeAccess
|
|
||||||
c.Id = user.Id
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
|
|
||||||
|
|
||||||
// Sign and get the complete encoded token as a string using the secret
|
|
||||||
tokenString, err := token.SignedString(config.AccessSecret())
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenString
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenerateRefresh(user *db.UserSchema) string {
|
|
||||||
c := BuildClaims(user)
|
|
||||||
c.ExpiresAt = jwt.NewNumericDate(time.Now().Add(REFRESH_EXPIRATION))
|
|
||||||
c.Type = TypeRefresh
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
|
|
||||||
|
|
||||||
// Sign and get the complete encoded token as a string using the secret
|
|
||||||
tokenString, err := token.SignedString(config.RefreshSecret())
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenString
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenerateVerifyEmail(user *db.UserSchema) string {
|
|
||||||
c := &Claims{}
|
|
||||||
c.Id = user.Id
|
|
||||||
c.Email = user.Email
|
|
||||||
c.IssuedAt = jwt.NewNumericDate(time.Now())
|
|
||||||
c.NotBefore = jwt.NewNumericDate(time.Now())
|
|
||||||
c.Issuer = config.JwtIssuer()
|
|
||||||
c.Audience = config.JwtAudience()
|
|
||||||
c.ExpiresAt = jwt.NewNumericDate(time.Now().Add(VERIFY_EMAIL_EXPIRATION))
|
|
||||||
c.Type = TypeVerifyEmail
|
|
||||||
c.Scope = "verify-email"
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
|
|
||||||
|
|
||||||
// Sign and get the complete encoded token as a string using the secret
|
|
||||||
tokenString, err := token.SignedString(config.EmailTokenSecret())
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenString
|
|
||||||
}
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
package token_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/db"
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/token"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ts string
|
|
||||||
|
|
||||||
// TODO Write actual unit tests
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
ts = token.GenerateAccess(&db.UserSchema{
|
|
||||||
Id: "id_1234",
|
|
||||||
Username: "myusername",
|
|
||||||
Email: "user@example.com",
|
|
||||||
Scope: "admin",
|
|
||||||
Policies: []string{"policy1", "policy2"},
|
|
||||||
})
|
|
||||||
m.Run()
|
|
||||||
}
|
|
||||||
func TestAccessIdentity(t *testing.T) {
|
|
||||||
if ts == "" {
|
|
||||||
t.Fatal("No token was created")
|
|
||||||
}
|
|
||||||
c, err := token.ValidateAccess(ts)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Expected valid token, got %v", err)
|
|
||||||
}
|
|
||||||
if c.Email != "user@example.com" || c.Id != "id_1234" || c.Username != "myusername" {
|
|
||||||
t.Errorf("Unexpected identity, got %v", c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func TestAccessScope(t *testing.T) {
|
|
||||||
c, err := token.ValidateAccess(ts)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Expected valid token, got %v", err)
|
|
||||||
}
|
|
||||||
if c.Scope != "admin" {
|
|
||||||
t.Errorf("Unexpected scope, expected %v got %v", "admin", c.Scope)
|
|
||||||
}
|
|
||||||
otherts := token.GenerateAccess(&db.UserSchema{
|
|
||||||
Id: "id_1234",
|
|
||||||
Username: "myusername",
|
|
||||||
Email: "user@example.com",
|
|
||||||
Policies: []string{"policy1", "policy2"},
|
|
||||||
})
|
|
||||||
c, err = token.ValidateAccess(otherts)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Expected valid token, got %v", err)
|
|
||||||
}
|
|
||||||
if c.Scope != "default" {
|
|
||||||
t.Errorf("Unexpected scope, expected %v got %v", "default", c.Scope)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func TestAccessPolicies(t *testing.T) {
|
|
||||||
ts := token.GenerateAccess(&db.UserSchema{
|
|
||||||
Id: "id_1234",
|
|
||||||
Username: "myusername",
|
|
||||||
Email: "user@example.com",
|
|
||||||
Scope: "admin",
|
|
||||||
Policies: []string{"policy1", "policy2"},
|
|
||||||
})
|
|
||||||
if ts == "" {
|
|
||||||
t.Error("No token was created")
|
|
||||||
}
|
|
||||||
c, err := token.ValidateAccess(ts)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Expected valid token, got %v", err)
|
|
||||||
}
|
|
||||||
if len(c.Policies) != 2 || c.Policies[0] != "policy1" || c.Policies[1] != "policy2" {
|
|
||||||
t.Errorf("Unexpected policies, got %v", c.Policies)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRefresh(t *testing.T) {
|
|
||||||
ts := token.GenerateRefresh(&db.UserSchema{
|
|
||||||
Id: "12345",
|
|
||||||
})
|
|
||||||
if ts == "" {
|
|
||||||
t.Error("No token was created")
|
|
||||||
}
|
|
||||||
c, err := token.ValidateRefresh(ts)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Expected valid token, got %v", err)
|
|
||||||
}
|
|
||||||
if c.Id != "12345" {
|
|
||||||
t.Errorf("Unexpected identity, got %v", c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
package token
|
|
||||||
|
|
||||||
const (
|
|
||||||
TypeRefresh = "Refresh"
|
|
||||||
TypeAccess = "Access"
|
|
||||||
TypeVerifyEmail = "VerifyEmail"
|
|
||||||
)
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
package token
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
"github.com/mnrva-dev/owltier.com/server/config"
|
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ValidateAccess(tokenString string) (*Claims, error) {
|
|
||||||
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
return config.AccessSecret(), nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if claims, ok := token.Claims.(*Claims); ok {
|
|
||||||
if !token.Valid {
|
|
||||||
return nil, fmt.Errorf("token is not valid")
|
|
||||||
}
|
|
||||||
if !slices.Contains(claims.Audience, "https://gosuimg.com") {
|
|
||||||
return nil, fmt.Errorf("unexpected audience value: %v", claims.Audience)
|
|
||||||
}
|
|
||||||
if claims.Type != "Access" {
|
|
||||||
return nil, fmt.Errorf("Unexpected token type: %v", claims.Type)
|
|
||||||
}
|
|
||||||
return claims, nil
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidateRefresh(tokenString string) (*Claims, error) {
|
|
||||||
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
return config.RefreshSecret(), nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
|
|
||||||
if !slices.Contains(claims.Audience, "https://gosuimg.com") {
|
|
||||||
return &Claims{}, fmt.Errorf("unexpected audience value: %v", claims.Audience)
|
|
||||||
}
|
|
||||||
if claims.Type != "Refresh" {
|
|
||||||
return &Claims{}, fmt.Errorf("Unexpected token type: %v", claims.Type)
|
|
||||||
}
|
|
||||||
return claims, nil
|
|
||||||
} else {
|
|
||||||
return &Claims{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidateVerifyEmail(tokenString string) (*Claims, error) {
|
|
||||||
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
return config.RefreshSecret(), nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
|
|
||||||
if !slices.Contains(claims.Audience, "https://gosuimg.com") {
|
|
||||||
return &Claims{}, fmt.Errorf("unexpected audience value: %v", claims.Audience)
|
|
||||||
}
|
|
||||||
if claims.Type != "VerifyEmail" {
|
|
||||||
return &Claims{}, fmt.Errorf("Unexpected token type: %v", claims.Type)
|
|
||||||
}
|
|
||||||
return claims, nil
|
|
||||||
} else {
|
|
||||||
return &Claims{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in new issue