mirror of
https://github.com/int128/kubelogin.git
synced 2026-05-18 05:46:42 +00:00
75 lines
2.0 KiB
Go
75 lines
2.0 KiB
Go
// Package jwtdecoder provides decoding a JWT.
|
|
package jwtdecoder
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/dgrijalva/jwt-go"
|
|
"github.com/google/wire"
|
|
"golang.org/x/xerrors"
|
|
)
|
|
|
|
//go:generate mockgen -destination mock_jwtdecoder/mock_jwtdecoder.go github.com/int128/kubelogin/pkg/adaptors/jwtdecoder Interface
|
|
|
|
// Set provides an implementation and interface.
|
|
var Set = wire.NewSet(
|
|
wire.Struct(new(Decoder), "*"),
|
|
wire.Bind(new(Interface), new(*Decoder)),
|
|
)
|
|
|
|
type Interface interface {
|
|
Decode(s string) (*Claims, error)
|
|
}
|
|
|
|
// Claims represents claims of a token.
|
|
type Claims struct {
|
|
Subject string
|
|
Expiry time.Time
|
|
Pretty map[string]string // string representation for debug and logging
|
|
}
|
|
|
|
type Decoder struct{}
|
|
|
|
// Decode returns the claims of the JWT.
|
|
// Note that this method does not verify the signature and always trust it.
|
|
func (d *Decoder) Decode(s string) (*Claims, error) {
|
|
parts := strings.Split(s, ".")
|
|
if len(parts) != 3 {
|
|
return nil, xerrors.Errorf("token contains an invalid number of segments")
|
|
}
|
|
b, err := jwt.DecodeSegment(parts[1])
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("could not decode the token: %w", err)
|
|
}
|
|
var claims jwt.StandardClaims
|
|
if err := json.NewDecoder(bytes.NewBuffer(b)).Decode(&claims); err != nil {
|
|
return nil, xerrors.Errorf("could not decode the json of token: %w", err)
|
|
}
|
|
var rawClaims map[string]interface{}
|
|
if err := json.NewDecoder(bytes.NewBuffer(b)).Decode(&rawClaims); err != nil {
|
|
return nil, xerrors.Errorf("could not decode the json of token: %w", err)
|
|
}
|
|
return &Claims{
|
|
Subject: claims.Subject,
|
|
Expiry: time.Unix(claims.ExpiresAt, 0),
|
|
Pretty: dumpRawClaims(rawClaims),
|
|
}, nil
|
|
}
|
|
|
|
func dumpRawClaims(rawClaims map[string]interface{}) map[string]string {
|
|
claims := make(map[string]string)
|
|
for k, v := range rawClaims {
|
|
switch v := v.(type) {
|
|
case float64:
|
|
claims[k] = fmt.Sprintf("%.f", v)
|
|
default:
|
|
claims[k] = fmt.Sprintf("%v", v)
|
|
}
|
|
}
|
|
return claims
|
|
}
|