64 lines
1.5 KiB
Go
64 lines
1.5 KiB
Go
|
package keypairs
|
||
|
|
||
|
import (
|
||
|
"encoding/base64"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// JWS is a parsed JWT, representation as signable/verifiable and human-readable parts
|
||
|
type JWS struct {
|
||
|
Header Object `json:"header"` // JSON
|
||
|
Claims Object `json:"claims"` // JSON
|
||
|
Protected string `json:"protected"` // base64
|
||
|
Payload string `json:"payload"` // base64
|
||
|
Signature string `json:"signature"` // base64
|
||
|
}
|
||
|
|
||
|
// JWSToJWT joins JWS parts into a JWT as {ProtectedHeader}.{SerializedPayload}.{Signature}.
|
||
|
func JWSToJWT(jwt *JWS) string {
|
||
|
return fmt.Sprintf(
|
||
|
"%s.%s.%s",
|
||
|
jwt.Protected,
|
||
|
jwt.Payload,
|
||
|
jwt.Signature,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
// JWTToJWS splits the JWT into its JWS segments
|
||
|
func JWTToJWS(jwt string) (jws *JWS) {
|
||
|
jwt = strings.TrimSpace(jwt)
|
||
|
parts := strings.Split(jwt, ".")
|
||
|
if 3 != len(parts) {
|
||
|
return nil
|
||
|
}
|
||
|
return &JWS{
|
||
|
Protected: parts[0],
|
||
|
Payload: parts[1],
|
||
|
Signature: parts[2],
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// DecodeComponents decodes JWS Header and Claims
|
||
|
func (jws *JWS) DecodeComponents() error {
|
||
|
protected, err := base64.RawURLEncoding.DecodeString(jws.Protected)
|
||
|
if nil != err {
|
||
|
return errors.New("invalid JWS header base64Url encoding")
|
||
|
}
|
||
|
if err := json.Unmarshal([]byte(protected), &jws.Header); nil != err {
|
||
|
return errors.New("invalid JWS header")
|
||
|
}
|
||
|
|
||
|
payload, err := base64.RawURLEncoding.DecodeString(jws.Payload)
|
||
|
if nil != err {
|
||
|
return errors.New("invalid JWS payload base64Url encoding")
|
||
|
}
|
||
|
if err := json.Unmarshal([]byte(payload), &jws.Claims); nil != err {
|
||
|
return errors.New("invalid JWS claims")
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|