a73x

internal/oidcprovider/jwt.go

Ref:   Size: 1.3 KiB   History

package oidcprovider

import (
	"crypto"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"time"
)

// signIDToken builds a compact JWS: base64url(header).base64url(claims).base64url(sig)
// with RSASSA-PKCS1-v1_5 over SHA-256. go-oidc on the other end verifies it
// against /jwks.json, which keeps this honest — no JWT library. Our tokens
// always carry email and email_verified:true, satisfying the spec's claims
// contract — the email is the account a password authenticates, verified by
// definition.
func (p *Provider) signIDToken(sub, email, audience string, now time.Time) (string, error) {
	header := map[string]any{"alg": "RS256", "typ": "JWT", "kid": p.kid}
	claims := map[string]any{
		"iss":            p.issuer,
		"sub":            sub,
		"aud":            audience,
		"iat":            now.Unix(),
		"exp":            now.Add(5 * time.Minute).Unix(),
		"email":          email,
		"email_verified": true,
	}
	seg := func(v any) string {
		b, _ := json.Marshal(v)
		return base64.RawURLEncoding.EncodeToString(b)
	}
	signing := seg(header) + "." + seg(claims)
	h := sha256.Sum256([]byte(signing))
	sig, err := rsa.SignPKCS1v15(nil, p.key, crypto.SHA256, h[:])
	if err != nil {
		return "", err
	}
	return signing + "." + base64.RawURLEncoding.EncodeToString(sig), nil
}