ultimate-media-tracker/server/token.go
Tronax 3f07c78316
feat: initial commit for media tracking software
- Setup C++/Qt6 desktop application structure
- Added initial Go proxy backend for TMDB/IGDB integration
2026-06-15 02:02:25 +02:00

68 lines
1.9 KiB
Go

package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"strings"
"time"
)
// appClaims is the payload of a desktop-app access token. These tokens are
// minted by this server after a successful Authentik login and are independent
// of the (short-lived) OIDC tokens, so a friend can paste one into the desktop
// app and keep using it until it expires.
type appClaims struct {
Subject string `json:"sub"`
Email string `json:"email"`
Expires int64 `json:"exp"` // unix seconds
}
// mintToken creates a stateless, HMAC-signed token of the form
// base64url(payload).base64url(sig). No server-side storage is needed.
func mintToken(secret []byte, sub, email string, ttl time.Duration) (string, error) {
payload := appClaims{
Subject: sub,
Email: email,
Expires: time.Now().Add(ttl).Unix(),
}
raw, err := json.Marshal(payload)
if err != nil {
return "", err
}
body := base64.RawURLEncoding.EncodeToString(raw)
sig := sign(secret, body)
return body + "." + sig, nil
}
// verifyToken validates the signature and expiry, returning the claims.
func verifyToken(secret []byte, token string) (*appClaims, error) {
parts := strings.SplitN(strings.TrimSpace(token), ".", 2)
if len(parts) != 2 {
return nil, errors.New("malformed token")
}
expected := sign(secret, parts[0])
if !hmac.Equal([]byte(expected), []byte(parts[1])) {
return nil, errors.New("bad signature")
}
raw, err := base64.RawURLEncoding.DecodeString(parts[0])
if err != nil {
return nil, errors.New("bad payload encoding")
}
var claims appClaims
if err := json.Unmarshal(raw, &claims); err != nil {
return nil, errors.New("bad payload")
}
if time.Now().Unix() >= claims.Expires {
return nil, errors.New("token expired")
}
return &claims, nil
}
func sign(secret []byte, body string) string {
m := hmac.New(sha256.New, secret)
m.Write([]byte(body))
return base64.RawURLEncoding.EncodeToString(m.Sum(nil))
}