...

Source file src/github.com/lestrrat-go/jwx/format.go

Documentation: github.com/lestrrat-go/jwx

     1  package jwx
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  )
     7  
     8  type FormatKind int
     9  
    10  const (
    11  	UnknownFormat FormatKind = iota
    12  	JWE
    13  	JWS
    14  	JWK
    15  	JWKS
    16  	JWT
    17  )
    18  
    19  type formatHint struct {
    20  	Payload    json.RawMessage `json:"payload"`    // Only in JWS
    21  	Signatures json.RawMessage `json:"signatures"` // Only in JWS
    22  	Ciphertext json.RawMessage `json:"ciphertext"` // Only in JWE
    23  	KeyType    json.RawMessage `json:"kty"`        // Only in JWK
    24  	Keys       json.RawMessage `json:"keys"`       // Only in JWKS
    25  	Audience   json.RawMessage `json:"aud"`        // Only in JWT
    26  }
    27  
    28  // GuessFormat is used to guess the format the given payload is in
    29  // using heuristics. See the type FormatKind for a full list of
    30  // possible types.
    31  //
    32  // This may be useful in determining your next action when you may
    33  // encounter a payload that could either be a JWE, JWS, or a plain JWT.
    34  //
    35  // Because JWTs are almost always JWS signed, you may be thrown off
    36  // if you pass what you think is a JWT payload to this function.
    37  // If the function is in the "Compact" format, it means it's a JWS
    38  // signed message, and its payload is the JWT. Therefore this function
    39  // will reuturn JWS, not JWT.
    40  //
    41  // This function requires an extra parsing of the payload, and therefore
    42  // may be inefficient if you call it every time before parsing.
    43  func GuessFormat(payload []byte) FormatKind {
    44  	// The check against kty, keys, and aud are something this library
    45  	// made up. for the distinctions between JWE and JWS, we used
    46  	// https://datatracker.ietf.org/doc/html/rfc7516#section-9.
    47  	//
    48  	// The above RFC described several ways to distinguish between
    49  	// a JWE and JWS JSON, but we're only using one of them
    50  
    51  	payload = bytes.TrimSpace(payload)
    52  	if len(payload) <= 0 {
    53  		return UnknownFormat
    54  	}
    55  
    56  	if payload[0] != '{' {
    57  		// Compact format. It's probably a JWS or JWE
    58  		sep := []byte{'.'} // I want to const this :/
    59  
    60  		// Note: this counts the number of occurrences of the
    61  		// separator, but the RFC talks about the number of segments.
    62  		// number of '.' == segments - 1, so that's why we have 2 and 4 here
    63  		switch count := bytes.Count(payload, sep); count {
    64  		case 2:
    65  			return JWS
    66  		case 4:
    67  			return JWE
    68  		default:
    69  			return UnknownFormat
    70  		}
    71  	}
    72  
    73  	// If we got here, we probably have JSON.
    74  	var h formatHint
    75  	if err := json.Unmarshal(payload, &h); err != nil {
    76  		return UnknownFormat
    77  	}
    78  
    79  	if h.Audience != nil {
    80  		return JWT
    81  	}
    82  	if h.KeyType != nil {
    83  		return JWK
    84  	}
    85  	if h.Keys != nil {
    86  		return JWKS
    87  	}
    88  	if h.Ciphertext != nil {
    89  		return JWE
    90  	}
    91  	if h.Signatures != nil && h.Payload != nil {
    92  		return JWS
    93  	}
    94  	return UnknownFormat
    95  }
    96  

View as plain text