jwt.bend relies on unsafe/foreign
raw source on the hub · import bend-kit-jwt@0.3.0.0/jwt.bend as Jwt
JSON Web Tokens: HS256/384/512, RS256, and ES256 compact JWS sign and verify, claim checks, and JWKS keys over Hairpin. Source: https://github.com/paymog/bend-kit/tree/main/jwt
6 imports
import Base import bend-kit-crypto@0.2.0.0/crypto.bend as Crypto import bend-kit-hairpin@0.3.0.0/hairpin.bend as Hairpin import bend-kit-http@0.32.0.0/http.bend as Http import 0x584fc27920487ceab242392391418d7f/json.bend as Json import 0x49814d83de8f70993a43e1002be29ecd/bytes.bend as Bytes
Types
type Alg source · line 14 · raw
Data
HS256Alg
HS384Alg
HS512Alg
RS256Alg
ES256Alg
type Key source · line 24 · raw
Type
Hmac: the shared secret, at least the digest's size (RFC 7518 §3.2). Pem: a PEM "PUBLIC KEY" to verify, or an unencrypted PEM private key to sign. Rsa, Ec: JWK public key parts as big-endian octets (RFC 7518 §6.3, §6.2 on P-256).
Hmac@secret:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Key
Pem@pem:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Key
Rsa@n:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @e:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Key
Ec@x:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @y:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Key
type Err source · line 30 · raw
Data
MalformedErr
AlgMismatchErr
CritErr
KeyTypeErr
WeakKeyErr
BadSigErr
BadClaimErr
ExpiredErr
NotYetErr
FutureErr
BadIssErr
BadAudErr
NoKeyErr
Crypto@code:U32 -> @why:String -> Err
Net@e:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Err -> Err
Status@code:U32 -> Err
type Policy source · line 49 · raw
Data
What verify accepts: the one alg, the issuer and audience when Some, and leeway seconds of clock skew.
Policy@alg:Alg -> @iss:Maybe<&2, String> -> @aud:Maybe<&2, String> -> @leeway:U32 -> Policy
type Lit source · line 161 · raw
Data
A NumericDate (RFC 7519 §2) rounded up to whole seconds and capped at the U32 top, or None when it is negative or has an exponent. Up is exact against a whole now: now >= t iff now >= ceil(t).
LStr@s:String -> Lit
LNum@t:Maybe<&2, U32> -> Lit
LStrs@xs:Maybe<&2, List<&2, String>> -> Lit
LOtherLit
type Field source · line 168 · raw
Data
One member: its name as octets, and what the checks need of its value.
Field@name:String -> @val:Lit -> Field
type Parts source · line 264 · raw
Type
A compact JWS: the header and claim members, the claims, the signing input, and the signature.
Parts@head:List<&2, Field> -> @facts:List<&2, Field> -> @claims:0x584fc27920487ceab242392391418d7f/json.Val -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Parts
type Jwk source · line 667 · raw
Data
A usable public key from a set: its kid, RSA or EC P-256, its alg ("" when the set gives none), and its two base64url parts (n and e, or x and y).
Jwk@kid:String -> @rsa:Bool -> @alg:String -> @a:String -> @b:String -> Jwk
type Jwks source · line 796 · raw
Data
A cached key set from the caller's own trusted url; a token never picks the url (jku and x5u are ignored). live: fetched once; at: the unix time of the last good fetch; ttl: seconds it stays fresh; tried: the unix time of the last fetch, good or not.
Jwks@url:String -> @ttl:U32 -> @live:Bool -> @at:U32 -> @tried:Maybe<&2, U32> -> @keys:List<&2, Jwk> -> Jwks
Definitions
def policy source · line 52 · raw
@a:Alg -> Policy
def iss source · line 55 · raw
@p:Policy -> @s:String -> Policy
def aud source · line 59 · raw
@p:Policy -> @s:String -> Policy
def leeway source · line 63 · raw
@p:Policy -> @+n:U32 -> Policy
def policy.alg source · line 67 · raw
@p:Policy -> Alg
def alg.name source · line 71 · raw
@a:Alg -> String
def b64u.push source · line 86 · raw
@+c:U32 -> @acc:String -> String
def b64u.go source · line 97 · raw
@s:String -> @acc:String -> String
def b64u source · line 104 · raw
@b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> String
def unb64u.c source · line 108 · raw
@+c:U32 -> U32
The standard alphabet's char for c. '+', '/', '=' and NUL become NUL, which no decoder accepts.
def unb64u.pad source · line 124 · raw
@+r:U32 -> @acc:String -> String
Padding for n mod 4 chars; 1 is never a whole group, so it gets a NUL.
def unb64u.go source · line 135 · raw
@s:String -> @acc:String -> @+n:U32 -> String
def unb64u.same source · line 142 · raw
@+s:String -> @r:Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes) -> Maybe<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
def unb64u.canon source · line 146 · raw
@+s:String -> @m:Maybe<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> Maybe<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
def unb64u source · line 154 · raw
@+s:String -> Maybe<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
Strict: only the URL-safe alphabet, no '=', and only the canonical text of its octets, so pad bits are 0.
def secs.digit source · line 171 · raw
@+acc:U32 -> @+d:U32 -> U32
def secs.up source · line 174 · raw
@+acc:U32 -> @frac:Bool -> U32
def secs.go source · line 178 · raw
@s:String -> @+acc:U32 -> @+frac:Bool -> @+point:Bool -> @+ok:Bool -> Maybe<&2, U32>
The JSON parser has checked the grammar, so only digits and one '.' need telling apart.
def secs source · line 189 · raw
@s:String -> Maybe<&2, U32>
def str.of source · line 192 · raw
@v:0x584fc27920487ceab242392391418d7f/json.Val -> Maybe<&2, String>
def strs.push source · line 199 · raw
@s:Maybe<&2, String> -> @acc:Maybe<&2, List<&2, String>> -> Maybe<&2, List<&2, String>>
def strs source · line 206 · raw
@xs:List<&1, 0x584fc27920487ceab242392391418d7f/json.Val> -> @acc:Maybe<&2, List<&2, String>> -> Maybe<&2, List<&2, String>>
def lit source · line 213 · raw
@v:0x584fc27920487ceab242392391418d7f/json.Val -> Lit
def fields source · line 225 · raw
@kvs:List<&1, Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, 0x584fc27920487ceab242392391418d7f/json.Val)> -> @acc:List<&2, Field> -> List<&2, Field>
An object's members, names as octets, last first.
def field source · line 232 · raw
@l:List<&2, Field> -> @+k:String -> Maybe<&2, Lit>
def has source · line 239 · raw
@l:List<&2, Field> -> @+k:String -> Bool
def dup source · line 247 · raw
@l:List<&2, Field> -> Bool
RFC 7515 §5.2 allows rejecting repeated names; a second "alg" is how parsers come to disagree.
def str source · line 254 · raw
@m:Maybe<&2, Lit> -> Maybe<&2, String>
def parse.objs source · line 267 · raw
@hf:List<&2, Field> -> @ff:List<&2, Field> -> @cv:0x584fc27920487ceab242392391418d7f/json.Val -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Result<&1, &1, Err, Parts>
def parse.json source · line 273 · raw
@h:Maybe<&1, 0x584fc27920487ceab242392391418d7f/json.Val> -> @f:Maybe<&1, 0x584fc27920487ceab242392391418d7f/json.Val> -> @c:Maybe<&1, 0x584fc27920487ceab242392391418d7f/json.Val> -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Result<&1, &1, Err, Parts>
def parse.claims source · line 281 · raw
@hb:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @r:Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes) -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Result<&1, &1, Err, Parts>
def parse.segs source · line 285 · raw
@h:Maybe<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @c:Maybe<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @s:Maybe<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Result<&1, &1, Err, Parts>
def parse.split source · line 293 · raw
@xs:List<&2, String> -> Result<&1, &1, Err, Parts>
def parse source · line 301 · raw
@token:String -> Result<&1, &1, Err, Parts>
Three strict base64url segments, the first two JSON objects with no repeated names.
def fail.if source · line 306 · raw
@bad:Bool -> @+e:Err -> Result<&1, &1, Err, Unit>
def head.alg source · line 313 · raw
@m:Maybe<&2, Lit> -> Result<&1, &1, Err, String>
def head.check source · line 322 · raw
@+a:Alg -> @+h:List<&2, Field> -> Result<&1, &1, Err, Unit>
The header's alg is exactly the pinned one, and it asks for no extension: crit (RFC 7515 §4.1.11) and b64 (RFC 7797) change how the token must be read, and neither is implemented.
def when source · line 328 · raw
@m:Maybe<&2, Lit> -> Result<&1, &1, Err, Maybe<&2, U32>>
def text source · line 337 · raw
@m:Maybe<&2, Lit> -> Result<&1, &1, Err, Maybe<&2, String>>
def auds source · line 347 · raw
@m:Maybe<&2, Lit> -> Result<&1, &1, Err, Maybe<&2, List<&2, String>>>
RFC 7519 §4.1.3: aud is one string or an array of them.
def late source · line 359 · raw
@+now:U32 -> @+lw:U32 -> @m:Maybe<&2, U32> -> Bool
exp (RFC 7519 §4.1.4): now must be before it; late by at least leeway fails.
def early source · line 367 · raw
@+now:U32 -> @+lw:U32 -> @m:Maybe<&2, U32> -> Bool
nbf and iat: at most leeway seconds in the future.
def octets source · line 374 · raw
@s:String -> String
def iss.bad source · line 377 · raw
@want:Maybe<&2, String> -> @got:Maybe<&2, String> -> Bool
def aud.has source · line 386 · raw
@l:List<&2, String> -> @+a:String -> Bool
def aud.bad source · line 394 · raw
@want:Maybe<&2, String> -> @got:Maybe<&2, List<&2, String>> -> Bool
RFC 7519 §4.1.3: a token with an aud that does not name us fails, as does one without aud when we want one.
def claims.check source · line 406 · raw
@p:Policy -> @+now:U32 -> @+c:List<&2, Field> -> Result<&1, &1, Err, Unit>
The registered claims of c at unix time now.
def inspect.parts source · line 420 · raw
@+p:Policy -> @+now:U32 -> @r:Result<&1, &1, Err, Parts> -> Result<&1, &1, Err, Unit>
def inspect source · line 430 · raw
@p:Policy -> @token:String -> @+now:U32 -> Result<&1, &1, Err, Unit>
The header and claims of token, without its signature: the pure half of verify.
def crypto.bytes source · line 435 · raw
@r:Result<&1, &1, Pair(U32, String), Pair(U32, Array<U32>)> -> Result<&1, &1, Err, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>
def crypto.ok source · line 442 · raw
@r:Result<&1, &1, Pair(U32, String), Bool> -> Result<&1, &1, Err, Bool>
def mac.if source · line 449 · raw
@weak:Bool -> @+alg:String -> @+kn:U32 -> @kb:Array<U32> -> @+dn:U32 -> @db:Array<U32> -> IO(Result<&1, &1, Err, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>)
def mac source · line 459 · raw
@+alg:String -> @+min:U32 -> @k:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>)
def mac.cmp source · line 464 · raw
@m:Result<&1, &1, Err, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, Bool>)
def mac.check source · line 475 · raw
@+alg:String -> @+min:U32 -> @k:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, Bool>)
The MAC compares in constant time.
def rsa.pem source · line 480 · raw
@p:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, Bool>)
def rsa.jwk source · line 488 · raw
@n:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @e:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, Bool>)
def ec.pem source · line 497 · raw
@p:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, Bool>)
def ec.jwk source · line 505 · raw
@x:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @y:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, Bool>)
def sig.check source · line 515 · raw
@a:Alg -> @key:Key -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, Bool>)
Does sig sign input under key for alg? A key of the wrong kind fails with KeyType before any crypto.
def rsa.sign source · line 534 · raw
@p:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>)
def ec.sign source · line 541 · raw
@p:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>)
def sig.make source · line 549 · raw
@a:Alg -> @key:Key -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes>)
The signature of input under key for alg. RS256 and ES256 sign with a PEM private key.
def header.kid source · line 566 · raw
@m:Maybe<&2, String> -> List<&1, Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, 0x584fc27920487ceab242392391418d7f/json.Val)>
def header source · line 574 · raw
@a:Alg -> @kid:Maybe<&2, String> -> 0x584fc27920487ceab242392391418d7f/json.Val
{"alg":..,"typ":"JWT"}, then "kid" when given.
def signing.input source · line 578 · raw
@a:Alg -> @kid:Maybe<&2, String> -> @body:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> String
header.body in base64url, body being the compact JSON claims: the text the signature covers.
def sign.done source · line 581 · raw
@+input:String -> @s:Result<&1, &1, Err, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> Result<&1, &1, Err, String>
def sign.obj source · line 589 · raw
@m:Maybe<&1, 0x584fc27920487ceab242392391418d7f/json.Val> -> Bool
verify accepts only an object with no repeated names, so sign makes no other kind.
def sign.if source · line 596 · raw
@ok:Bool -> @+a:Alg -> @key:Key -> @kid:Maybe<&2, String> -> @body:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, String>)
def sign.body source · line 606 · raw
@+a:Alg -> @key:Key -> @kid:Maybe<&2, String> -> @r:Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes) -> IO(Result<&1, &1, Err, String>)
def sign source · line 612 · raw
@+a:Alg -> @key:Key -> @kid:Maybe<&2, String> -> @claims:0x584fc27920487ceab242392391418d7f/json.Val -> IO(Result<&1, &1, Err, String>)
A compact token of claims signed with key for a; kid names the key in the header. Claims that are not an object, or repeat a name, fail with BadClaim.
def claims.done source · line 615 · raw
@r:Result<&1, &1, Err, Unit> -> @v:0x584fc27920487ceab242392391418d7f/json.Val -> Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>
def check.sig source · line 622 · raw
@ok:Bool -> @+p:Policy -> @+now:U32 -> @+f:List<&2, Field> -> @v:0x584fc27920487ceab242392391418d7f/json.Val -> Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>
def check.done source · line 629 · raw
@s:Result<&1, &1, Err, Bool> -> @+p:Policy -> @+now:U32 -> @+f:List<&2, Field> -> @v:0x584fc27920487ceab242392391418d7f/json.Val -> Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>
def check.pinned source · line 637 · raw
@ok:Result<&1, &1, Err, Unit> -> @+p:Policy -> @key:Key -> @+now:U32 -> @+f:List<&2, Field> -> @v:0x584fc27920487ceab242392391418d7f/json.Val -> @input:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> @sig:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> IO(Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>)
def check source · line 648 · raw
@+p:Policy -> @key:Key -> @+now:U32 -> @parts:Parts -> IO(Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>)
The pinned alg, then the signature, then the claims.
def verify.parsed source · line 652 · raw
@+p:Policy -> @key:Key -> @+now:U32 -> @r:Result<&1, &1, Err, Parts> -> IO(Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>)
def verify source · line 660 · raw
@+p:Policy -> @key:Key -> @token:String -> @+now:U32 -> IO(Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>)
The claims of token when it is signed by key under p's alg and its claims hold at unix time now.
def jwk.two source · line 670 · raw
@+rsa:Bool -> @+kid:String -> @+alg:String -> @a:Maybe<&2, String> -> @b:Maybe<&2, String> -> Maybe<&2, Jwk>
def jwk.alg source · line 678 · raw
@m:Maybe<&2, Lit> -> String
An alg member that is not a string can match no pinned alg.
def jwk.use source · line 687 · raw
@m:Maybe<&2, Lit> -> Maybe<&2, Unit>
def jwk.kty source · line 696 · raw
@+kty:String -> @+kid:String -> @+f:List<&2, Field> -> Maybe<&2, Jwk>
def jwk.fields source · line 702 · raw
@+f:List<&2, Field> -> Maybe<&2, Jwk>
def jwk.of source · line 710 · raw
@v:0x584fc27920487ceab242392391418d7f/json.Val -> Maybe<&2, Jwk>
def jwk.push source · line 717 · raw
@m:Maybe<&2, Jwk> -> @acc:List<&2, Jwk> -> List<&2, Jwk>
def jwks.go source · line 724 · raw
@xs:List<&1, 0x584fc27920487ceab242392391418d7f/json.Val> -> @acc:List<&2, Jwk> -> List<&2, Jwk>
def jwks.arr source · line 731 · raw
@m:Maybe<&1, 0x584fc27920487ceab242392391418d7f/json.Val> -> Maybe<&2, List<&2, Jwk>>
def jwks.doc source · line 738 · raw
@m:Maybe<&1, 0x584fc27920487ceab242392391418d7f/json.Val> -> Maybe<&2, List<&2, Jwk>>
def jwks.parse source · line 747 · raw
@b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Maybe<&2, List<&2, Jwk>>
The signing keys of a JWK Set document; members it cannot use (enc keys, other curves, oct) are skipped. None when the document is not {"keys": [...]}.
def fam source · line 750 · raw
@a:Alg -> U32
def jwk.fits source · line 759 · raw
@k:Jwk -> @+kid:String -> @+a:Alg -> Bool
def jwk.pick source · line 765 · raw
@ks:List<&2, Jwk> -> @+kid:String -> @+a:Alg -> Maybe<&2, Jwk>
The first key named kid that can check alg a. RFC 7515 §4.1.4 leaves kid matching to exact comparison.
def jwk.key.of source · line 772 · raw
@rsa:Bool -> @a:Maybe<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> @b:Maybe<&1, 0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes> -> Result<&1, &1, Err, Key>
def jwk.key source · line 782 · raw
@k:Jwk -> Result<&1, &1, Err, Key>
A set member as a verify key.
def jwk.found source · line 786 · raw
@m:Maybe<&2, Jwk> -> Result<&1, &1, Err, Key>
def jwks source · line 799 · raw
@url:String -> @+ttl:U32 -> Jwks
def jwks.keys source · line 802 · raw
@s:Jwks -> List<&2, Jwk>
def fetch.keys source · line 806 · raw
@m:Maybe<&2, List<&2, Jwk>> -> @c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @+now:U32 -> Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Unit>))
def fetch.body source · line 814 · raw
@ok:Bool -> @+status:U32 -> @c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @+now:U32 -> @b:0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes -> Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Unit>))
def fetch.res source · line 822 · raw
@c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @+now:U32 -> @r:Result<&1, &1, 0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Err, 0x6a946b742ab6f76f0ba5b90b14da52ad/http.Res> -> Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Unit>))
def fetch.done source · line 830 · raw
@s:Jwks -> @+now:U32 -> @x:Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Result<&1, &1, 0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Err, 0x6a946b742ab6f76f0ba5b90b14da52ad/http.Res>) -> Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Unit>))
def fetch source · line 836 · raw
@c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @+now:U32 -> IO(Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Unit>)))
GET the set now. On any failure the client and the old keys come back, with only tried moved to now.
def key.after.r source · line 842 · raw
@r:Result<&1, &1, Err, Unit> -> @c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @+s:Jwks -> @+kid:String -> @+a:Alg -> Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Key>))
def key.after source · line 850 · raw
@+kid:String -> @+a:Alg -> @x:Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Unit>)) -> Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Key>))
def key.refetch source · line 855 · raw
@go:Bool -> @c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @+kid:String -> @+a:Alg -> @+now:U32 -> IO(Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Key>)))
def key.go source · line 865 · raw
@cached:Bool -> @+go:Bool -> @c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @found:Maybe<&2, Jwk> -> @+kid:String -> @+a:Alg -> @+now:U32 -> IO(Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Key>)))
def since source · line 873 · raw
@+now:U32 -> @m:Maybe<&2, U32> -> U32
def key source · line 883 · raw
@c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @+kid:String -> @+a:Alg -> @+now:U32 -> IO(Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Key>)))
The verify key named kid for alg a. A known key stays usable through the 60 s fetch cooldown even when ttl is shorter. After that, refresh a stale set or an unknown kid at most once a minute. ponytail: fixed 60 s cooldown; make it a Jwks field if an issuer rotates faster.
def jwks.run source · line 890 · raw
@r:Result<&1, &1, Err, Key> -> @c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @+p:Policy -> @+now:U32 -> @parts:Parts -> IO(Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>)))
def jwks.keyed source · line 900 · raw
@+p:Policy -> @+now:U32 -> @parts:Parts -> @x:Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, Key>)) -> IO(Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>)))
def jwks.kid source · line 905 · raw
@k:Maybe<&2, String> -> @+p:Policy -> @c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @+now:U32 -> @parts:Parts -> IO(Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>)))
def jwks.pinned source · line 915 · raw
@ok:Result<&1, &1, Err, Unit> -> @+p:Policy -> @c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @+now:U32 -> @+h:List<&2, Field> -> @parts:Parts -> IO(Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>)))
def jwks.parsed source · line 923 · raw
@+p:Policy -> @c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @+now:U32 -> @r:Result<&1, &1, Err, Parts> -> IO(Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>)))
def verify.jwks source · line 933 · raw
@+p:Policy -> @c:0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client -> @s:Jwks -> @token:String -> @+now:U32 -> IO(Pair(0x5f997a9351e7133e43ba9611e734f8a6/hairpin.Client, Pair(Jwks, Result<&1, &1, Err, 0x584fc27920487ceab242392391418d7f/json.Val>)))
verify with the key the token's kid names in the set. The alg is pinned before any fetch. The client and the set (refreshed or not) always come back.