-
Notifications
You must be signed in to change notification settings - Fork 394
Support custom json and base64 encoders for Token and Parser #301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
90d315c
8089d9e
7a5e5d6
f0fa303
7684d3e
3ae2a4a
f64f460
5e2ab08
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,20 +2,21 @@ package jwt | |
|
||
import "io" | ||
|
||
// Base64Encoder is an interface that allows to implement custom Base64 encoding | ||
// algorithms. | ||
type Base64EncodeFunc func(src []byte) string | ||
type Base64Encoding interface { | ||
EncodeToString(src []byte) string | ||
DecodeString(s string) ([]byte, error) | ||
} | ||
|
||
// Base64Decoder is an interface that allows to implement custom Base64 decoding | ||
// algorithms. | ||
type Base64DecodeFunc func(s string) ([]byte, error) | ||
type Stricter[T Base64Encoding] interface { | ||
Strict() T | ||
} | ||
|
||
// JSONEncoder is an interface that allows to implement custom JSON encoding | ||
// algorithms. | ||
// JSONMarshalFunc is an function type that allows to implement custom JSON | ||
// encoding algorithms. | ||
type JSONMarshalFunc func(v any) ([]byte, error) | ||
|
||
// JSONUnmarshal is an interface that allows to implement custom JSON unmarshal | ||
// algorithms. | ||
// JSONUnmarshalFunc is an function type that allows to implement custom JSON | ||
// unmarshal algorithms. | ||
type JSONUnmarshalFunc func(data []byte, v any) error | ||
|
||
type JSONDecoder interface { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs a comment because its a public interface |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,12 +26,11 @@ type Parser struct { | |
type decoders struct { | ||
jsonUnmarshal JSONUnmarshalFunc | ||
jsonNewDecoder JSONNewDecoderFunc[JSONDecoder] | ||
base64Decode Base64DecodeFunc | ||
|
||
// This field is disabled when using a custom base64 encoder. | ||
decodeStrict bool | ||
rawUrlBase64Encoding Base64Encoding | ||
urlBase64Encoding Base64Encoding | ||
|
||
// This field is disabled when using a custom base64 encoder. | ||
decodeStrict bool | ||
decodePaddingAllowed bool | ||
} | ||
|
||
|
@@ -227,22 +226,35 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke | |
// take into account whether the [Parser] is configured with additional options, | ||
// such as [WithStrictDecoding] or [WithPaddingAllowed]. | ||
func (p *Parser) DecodeSegment(seg string) ([]byte, error) { | ||
if p.base64Decode != nil { | ||
return p.base64Decode(seg) | ||
var encoding Base64Encoding | ||
if p.rawUrlBase64Encoding != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same comment about stage where custom base64 encoder function set. We can set p.rawUrlBase64Encoding to base64.RawURLEncoding or custom function on Parser creation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added this as a safe guard if people ever came across the crazy idea to directly create a Parser struct, which is unfortunately possible because we did not hide it behind an interface. But yes, if we assume that in the case you are doing that you REALLY know what you are doing we can do it in the init There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that sounds reasonable. |
||
encoding = p.rawUrlBase64Encoding | ||
} else { | ||
encoding = base64.RawURLEncoding | ||
} | ||
|
||
encoding := base64.RawURLEncoding | ||
|
||
if p.decodePaddingAllowed { | ||
if l := len(seg) % 4; l > 0 { | ||
seg += strings.Repeat("=", 4-l) | ||
} | ||
encoding = base64.URLEncoding | ||
|
||
if p.urlBase64Encoding != nil { | ||
encoding = p.urlBase64Encoding | ||
} else { | ||
encoding = base64.URLEncoding | ||
} | ||
} | ||
|
||
if p.decodeStrict { | ||
encoding = encoding.Strict() | ||
// For now we can only support the standard library here because of the | ||
// current state of the type parameter system | ||
stricter, ok := encoding.(Stricter[*base64.Encoding]) | ||
if !ok { | ||
return nil, newError("strict mode is only supported in encoding/base64", ErrUnsupported) | ||
} | ||
encoding = stricter.Strict() | ||
} | ||
|
||
return encoding.DecodeString(seg) | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,8 +39,8 @@ type Token struct { | |
} | ||
|
||
type encoders struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. its not private, but still we probably could use some comments here, especially for this outer struct |
||
jsonMarshal JSONMarshalFunc // jsonEncoder is the custom json encoder/decoder | ||
base64Encode Base64EncodeFunc // base64Encoder is the custom base64 encoder/decoder | ||
jsonMarshal JSONMarshalFunc // jsonEncoder is the custom json encoder/decoder | ||
base64Encoding Base64Encoding // base64Encoder is the custom base64 encoding | ||
} | ||
|
||
// New creates a new [Token] with the specified signing method and an empty map | ||
|
@@ -114,12 +114,12 @@ func (t *Token) SigningString() (string, error) { | |
// [TokenOption]. Therefore, this function exists as a method of [Token], rather | ||
// than a global function. | ||
func (t *Token) EncodeSegment(seg []byte) string { | ||
var enc Base64EncodeFunc | ||
if t.base64Encode != nil { | ||
enc = t.base64Encode | ||
var enc Base64Encoding | ||
if t.base64Encoding != nil { | ||
enc = t.base64Encoding | ||
} else { | ||
enc = base64.RawURLEncoding.EncodeToString | ||
enc = base64.RawURLEncoding | ||
} | ||
|
||
return enc(seg) | ||
return enc.EncodeToString(seg) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,8 +10,8 @@ func WithJSONEncoder(f JSONMarshalFunc) TokenOption { | |
} | ||
} | ||
|
||
func WithBase64Encoder(f Base64EncodeFunc) TokenOption { | ||
func WithBase64Encoder(enc Base64Encoding) TokenOption { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing comments here |
||
return func(token *Token) { | ||
token.base64Encode = f | ||
token.base64Encoding = enc | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This at least needs a comment if we want to keep It exported, it could probably also be private I guess