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
}