chore: initial project scaffold with admin web, backend, desktop client, and deployment setup
Add monorepo structure for NexaVPN WireGuard control plane including: - .gitignore for node_modules, build artifacts, and environment files - README with project overview, monorepo layout, and quick start guide - Admin web UI with React, Vite, TypeScript, and nginx reverse proxy - API client with type definitions for users, devices, policies, gateways, and audit logs - Admin pages for dashboard, users, devices, policies, g
This commit is contained in:
77
backend/internal/auth/token.go
Normal file
77
backend/internal/auth/token.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func NewRefreshToken() (plain string, hashed string, err error) {
|
||||
raw := make([]byte, 32)
|
||||
if _, err = rand.Read(raw); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
plain = base64.RawURLEncoding.EncodeToString(raw)
|
||||
sum := sha256.Sum256([]byte(plain))
|
||||
hashed = base64.RawURLEncoding.EncodeToString(sum[:])
|
||||
return plain, hashed, nil
|
||||
}
|
||||
|
||||
func SignAccessToken(secret, issuer string, ttl time.Duration, claims Claims) (string, error) {
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"iss": issuer,
|
||||
"sub": claims.UserID.String(),
|
||||
"username": claims.Username,
|
||||
"role": claims.Role,
|
||||
"session_id": claims.Session.String(),
|
||||
"exp": time.Now().Add(ttl).Unix(),
|
||||
"iat": time.Now().Unix(),
|
||||
})
|
||||
|
||||
return token.SignedString([]byte(secret))
|
||||
}
|
||||
|
||||
func ParseAccessToken(secret string, tokenString string) (Claims, error) {
|
||||
claims := Claims{}
|
||||
|
||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) {
|
||||
return []byte(secret), nil
|
||||
})
|
||||
if err != nil || !token.Valid {
|
||||
return claims, err
|
||||
}
|
||||
|
||||
mapClaims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
return claims, jwt.ErrTokenMalformed
|
||||
}
|
||||
|
||||
subject, ok := mapClaims["sub"].(string)
|
||||
if !ok {
|
||||
return claims, jwt.ErrTokenMalformed
|
||||
}
|
||||
sessionValue, ok := mapClaims["session_id"].(string)
|
||||
if !ok {
|
||||
return claims, jwt.ErrTokenMalformed
|
||||
}
|
||||
|
||||
userID, err := uuid.Parse(subject)
|
||||
if err != nil {
|
||||
return claims, err
|
||||
}
|
||||
sessionID, err := uuid.Parse(sessionValue)
|
||||
if err != nil {
|
||||
return claims, err
|
||||
}
|
||||
|
||||
claims.UserID = userID
|
||||
claims.Session = sessionID
|
||||
claims.Username, _ = mapClaims["username"].(string)
|
||||
claims.Role, _ = mapClaims["role"].(string)
|
||||
return claims, nil
|
||||
}
|
||||
Reference in New Issue
Block a user