Issue daemon auth tokens (mdt_) on pairing session claim, bound to workspace_id + daemon_id with 1-year expiry. Add DaemonAuth middleware that validates these tokens and falls back to JWT/PAT for backward compatibility. Apply middleware to all daemon routes except pairing endpoints.
53 lines
1.2 KiB
Go
53 lines
1.2 KiB
Go
package auth
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
)
|
|
|
|
const defaultJWTSecret = "multica-dev-secret-change-in-production"
|
|
|
|
var (
|
|
jwtSecret []byte
|
|
jwtSecretOnce sync.Once
|
|
)
|
|
|
|
func JWTSecret() []byte {
|
|
jwtSecretOnce.Do(func() {
|
|
secret := os.Getenv("JWT_SECRET")
|
|
if secret == "" {
|
|
secret = defaultJWTSecret
|
|
}
|
|
jwtSecret = []byte(secret)
|
|
})
|
|
|
|
return jwtSecret
|
|
}
|
|
|
|
// GeneratePATToken creates a new personal access token: "mul_" + 40 random hex chars.
|
|
func GeneratePATToken() (string, error) {
|
|
b := make([]byte, 20) // 20 bytes = 40 hex chars
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "", fmt.Errorf("generate PAT token: %w", err)
|
|
}
|
|
return "mul_" + hex.EncodeToString(b), nil
|
|
}
|
|
|
|
// GenerateDaemonToken creates a new daemon auth token: "mdt_" + 40 random hex chars.
|
|
func GenerateDaemonToken() (string, error) {
|
|
b := make([]byte, 20) // 20 bytes = 40 hex chars
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "", fmt.Errorf("generate daemon token: %w", err)
|
|
}
|
|
return "mdt_" + hex.EncodeToString(b), nil
|
|
}
|
|
|
|
// HashToken returns the hex-encoded SHA-256 hash of a token string.
|
|
func HashToken(token string) string {
|
|
h := sha256.Sum256([]byte(token))
|
|
return hex.EncodeToString(h[:])
|
|
}
|