Files

45 lines
1.3 KiB
Go

package testpds
import (
"encoding/base64"
"encoding/json"
"fmt"
"time"
)
// signServiceAuthJWT mints a JWT in the shape Hold expects, signed with the
// identity's K-256 signing key. The header advertises ES256K (the algorithm
// ATProto PDSes use). The Hold's ValidateServiceToken in pkg/hold/pds/auth.go
// parses the JWT manually rather than via golang-jwt, so we don't need to
// match golang-jwt's exact byte ordering — just produce well-formed
// base64url(JSON).header.base64url(JSON).payload.base64url(sig).
func (i *Identity) signServiceAuthJWT(aud, lxm string, exp time.Time) (string, error) {
header := map[string]string{"alg": "ES256K", "typ": "JWT"}
headerJSON, err := json.Marshal(header)
if err != nil {
return "", fmt.Errorf("marshal header: %w", err)
}
payload := map[string]any{
"iss": i.DID.String(),
"aud": aud,
"exp": exp.Unix(),
"lxm": lxm,
"iat": time.Now().Unix(),
}
payloadJSON, err := json.Marshal(payload)
if err != nil {
return "", fmt.Errorf("marshal payload: %w", err)
}
signingInput := base64.RawURLEncoding.EncodeToString(headerJSON) + "." +
base64.RawURLEncoding.EncodeToString(payloadJSON)
sig, err := i.SigningKey.HashAndSign([]byte(signingInput))
if err != nil {
return "", fmt.Errorf("sign: %w", err)
}
return signingInput + "." + base64.RawURLEncoding.EncodeToString(sig), nil
}