bend-kit-oauth2 Releases (13): 0.11.0.1 0xe5e42278c17e49602dedb920b82e4180 indexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.11.0.1 0.11.0.0 0x2641107ee7dd9bd258f343603078bef7 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.11.0.0 0.10.0.0 0x7c44e59172cf63a32824734bd35170d6 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.10.0.0 0.9.0.0 0x0151fe289d815d7345f3454f4b990783 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.9.0.0 0.8.0.0 0xcbd95973879f71cbbcfb4430661a74e5 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.8.0.0 0.7.0.0 0x133c94679e6285dbc1d7c2844e345903 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.7.0.0 0.6.0.0 0xfc88db86b109ba9492937719d9ae5f93 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.6.0.0 0.5.0.0 0x2c2681c0372e77febdfc5caef5dd9532 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.5.0.0 0.4.0.0 0x0f90100b1a0e7868f46c9e25157cce75 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.4.0.0 0.3.0.1 0xe282844a9561d11ea155f1b1ad7e9f46 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.3.0.1 0.3.0.0 0x3cbf4225d9d2a6e8a699592f4c12079f unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.3.0.0 0.2.0.0 0x69e07648b7e57fd59ce9869cc3d78062 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.2.0.0 0.1.0.0 0xb5bcbf15ce587f8e398134eb3e3845fe unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-oauth2@0.1.0.0 Definitions (56): Oauth2.Config (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=Config) # RFC 6749 and RFC 7636. Text is a String of code points; form values go out as UTF-8. # token: the token endpoint URL. secret: "" for a public client, which sends client_id in the body; # a confidential client authenticates with HTTP Basic (RFC 6749 §2.3.1). type Config is Data: Config{token: String, id: String, secret: String} Oauth2.Token (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=Token) # kind: token_type, as "Bearer". refresh: "" for none. scope: "" when the server did not say. # expires: when the access token lapses, counted from just before the request; None without expires_in. type Token is Data: Token{access: String, kind: String, refresh: String, scope: String, expires: Maybe<&2, Time.Instant>} Oauth2.Err (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=Err) # ErrNet: the request did not complete. ErrOAuth: an RFC 6749 §5.2 error with its status, or a §4.1.2.1 # error in a callback, status 0. ErrReply: not a Bearer token response, with its status and text. ErrState: the # callback's state is not ours (§10.12). ErrCrypto: the random source or SHA-256 failed. ErrExpired: the # token lapsed and has no refresh token. type Err is Data: ErrNet{e: Hairpin.Err} ErrOAuth{status: U32, code: String, why: String} ErrReply{status: U32, body: String} ErrState{} ErrCrypto{code: U32, why: String} ErrExpired{} Oauth2.b64url.ch (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=b64url.ch) def b64url.ch(+c: U32, t: String) -> String: Oauth2.b64url.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=b64url.go) def b64url.go(s: String) -> String: Oauth2.b64url (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=b64url) # Base64url without padding (RFC 4648 §5, RFC 7636 Appendix A). def b64url(b: Bytes.Bytes) -> String: Oauth2.utf8 (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=utf8) def utf8(+s: String) -> String: Oauth2.field (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=field) def field(m: Map<&2, String>, k: String, +v: String) -> Map<&2, String>: Oauth2.scoped (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=scoped) def scoped(+scope: String, +m: Map<&2, String>) -> Map<&2, String>: Oauth2.form (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=form) def form(+k: String, +v: String) -> Map<&2, String>: Oauth2.basic (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=basic) # RFC 6749 §2.3.1: id and secret are form-encoded before base64. def basic(+id: String, +secret: String) -> String: Oauth2.auth.headers (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=auth.headers) def auth.headers(+id: String, +secret: String) -> Map<&2, List<&2, String>>: Oauth2.auth.body (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=auth.body) def auth.body(+id: String, +secret: String, +m: Map<&2, String>) -> Map<&2, String>: Oauth2.body (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=body) # The form body of a token request from cfg's client. def body(+id: String, +secret: String, m: Map<&2, String>) -> String: Oauth2.Got (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=Got) type Got is Data: Got{access: String, kind: String, refresh: String, scope: String, expires: String, error: String, desc: String} Oauth2.got.put (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=got.put) def got.put(g: Got, +k: String, +v: String) -> Got: Oauth2.got.text (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=got.text) # A string's text, or a number's, as some servers send expires_in as "3600". def got.text(v: Json.Val) -> String: Oauth2.got.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=got.go) def got.go(kvs: List<&1, Bytes.Bytes & Json.Val>, g: Got) -> Got: Oauth2.got.obj (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=got.obj) def got.obj(v: Json.Val) -> Maybe<&2, Got>: Oauth2.got (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=got) def got(m: Maybe<&1, Json.Val>) -> Maybe<&2, Got>: Oauth2.expiry (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=expiry) def expiry(now: Time.Instant, m: Maybe<&2, U32>) -> Maybe<&2, Time.Instant>: Oauth2.good (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=good) # A 2xx with an access token of type Bearer (RFC 6750 §4, case-insensitive), the only kind request sends. def good(+status: U32, g: Got) -> Bool: Oauth2.token.pick (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=token.pick) # §6: a refresh reply without refresh_token keeps the old one. b: the body, decoded only for an error. def token.pick(ok: Bool, +status: U32, +old: String, now: Time.Instant, b: Bytes.Bytes, g: Got) -> Result<&1, &1, Err, Token>: Oauth2.token.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=token.of) def token.of(+status: U32, +old: String, now: Time.Instant, b: Bytes.Bytes, m: Maybe<&2, Got>) -> Result<&1, &1, Err, Token>: Oauth2.parse.copy (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=parse.copy) def parse.copy(+status: U32, +old: String, now: Time.Instant, r: Bytes.Bytes & Bytes.Bytes) -> Result<&1, &1, Err, Token>: Oauth2.parse (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=parse) # A token endpoint's reply at status, requested at now. old: the refresh token to keep when none comes back. def parse(+status: U32, +old: String, now: Time.Instant, b: Bytes.Bytes) -> Result<&1, &1, Err, Token>: Oauth2.reply (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=reply) def reply(+old: String, now: Time.Instant, r: Result<&1, &1, Hairpin.Err, Http.Res>) -> Result<&1, &1, Err, Token>: Oauth2.grant.done (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=grant.done) def grant.done(+old: String, now: Time.Instant, x: Hairpin.Client & Result<&1, &1, Hairpin.Err, Http.Res>) -> Hairpin.Client & Result<&1, &1, Err, Token>: Oauth2.grant (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=grant) # POST m to the token endpoint. Hairpin sends a POST once. def grant(h: Hairpin.Client, cfg: Config, m: Map<&2, String>, +old: String) -> IO(Hairpin.Client & Result<&1, &1, Err, Token>): Oauth2.client_credentials (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=client_credentials) # RFC 6749 §4.4. scope: "" for the server's default. def client_credentials(h: Hairpin.Client, cfg: Config, +scope: String) -> IO(Hairpin.Client & Result<&1, &1, Err, Token>): Oauth2.code (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=code) # RFC 6749 §4.1.3 with RFC 7636 §4.5: the code from callback, the same redirect_uri, and the verifier. def code(h: Hairpin.Client, cfg: Config, +code: String, +redirect: String, +verifier: String) -> IO(Hairpin.Client & Result<&1, &1, Err, Token>): Oauth2.refresh.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=refresh.go) def refresh.go(none: Bool, h: Hairpin.Client, cfg: Config, +r: String, +scope: String) -> IO(Hairpin.Client & Result<&1, &1, Err, Token>): Oauth2.refresh (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=refresh) # RFC 6749 §6. scope: "" keeps the granted scope. ErrExpired when tok has no refresh token. def refresh(h: Hairpin.Client, cfg: Config, tok: Token, +scope: String) -> IO(Hairpin.Client & Result<&1, &1, Err, Token>): Oauth2.expiring.at (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=expiring.at) def expiring.at(e: Maybe<&2, Time.Instant>, now: Time.Instant, +skew: U32) -> Bool: Oauth2.expiring (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=expiring) # Does tok lapse within skew seconds of now? A token without expires_in never does. def expiring(tok: Token, now: Time.Instant, +skew: U32) -> Bool: Oauth2.fresh.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=fresh.go) def fresh.go(due: Bool, h: Hairpin.Client, cfg: Config, +tok: Token) -> IO(Hairpin.Client & Result<&1, &1, Err, Token>): Oauth2.fresh (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=fresh) # tok, or a refreshed one when it lapses within skew seconds. def fresh(h: Hairpin.Client, cfg: Config, +tok: Token, +skew: U32) -> IO(Hairpin.Client & Result<&1, &1, Err, Token>): Oauth2.fresh.cc.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=fresh.cc.go) def fresh.cc.go(due: Bool, h: Hairpin.Client, cfg: Config, +scope: String, +tok: Token) -> IO(Hairpin.Client & Result<&1, &1, Err, Token>): Oauth2.fresh.cc (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=fresh.cc) # tok, or a new client-credentials token when it lapses within skew seconds (§4.4.3: no refresh token). def fresh.cc(h: Hairpin.Client, cfg: Config, +scope: String, +tok: Token, +skew: U32) -> IO(Hairpin.Client & Result<&1, &1, Err, Token>): Oauth2.random.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=random.of) def random.of(r: Result<&1, &1, U32 & String, U32 & Array>) -> Result<&1, &1, Err, String>: Oauth2.random (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=random) # n octets from the OS secure random source, as base64url. def random(+n: U32) -> IO(Result<&1, &1, Err, String>): Oauth2.verifier (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=verifier) # §4.1: 32 random octets, 43 unreserved chars. def verifier() -> IO(Result<&1, &1, Err, String>): Oauth2.state (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=state) # An unguessable state for the authorization request (RFC 6749 §10.12). def state() -> IO(Result<&1, &1, Err, String>): Oauth2.challenge.words (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=challenge.words) def challenge.words(b: Bytes.Bytes) -> IO(Result<&1, &1, Err, String>): Oauth2.challenge (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=challenge) # §4.2 S256: BASE64URL(SHA256(ASCII(verifier))). def challenge(+verifier: String) -> IO(Result<&1, &1, Err, String>): Oauth2.qmark (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=qmark) def qmark(s: String) -> Bool: Oauth2.authorize.url (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=authorize.url) # RFC 6749 §4.1.1 with RFC 7636 §4.3: the URL to send the user to. endpoint may carry its own query. def authorize.url(cfg: Config, +endpoint: String, +redirect: String, +scope: String, +state: String, +challenge: String) -> String: Oauth2.param.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=param.of) def param.of(r: Map<&2, String> & String) -> String: Oauth2.param (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=param) def param(+m: Map<&2, String>, k: String) -> String: Oauth2.callback.pick (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=callback.pick) def callback.pick(+err: String, desc: String, +got: String, +code: String, +state: String) -> Result<&1, &1, Err, String>: Oauth2.callback.m (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=callback.m) def callback.m(+state: String, m: Maybe<&2, Url.Url>) -> Result<&1, &1, Err, String>: Oauth2.callback.frag (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=callback.frag) def callback.frag(+state: String, r: String & String) -> Result<&1, &1, Err, String>: Oauth2.callback.q (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=callback.q) def callback.q(+state: String, r: String & String) -> Result<&1, &1, Err, String>: Oauth2.callback (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=callback) # §4.1.2: the code in the redirect to redirect_uri, once its state matches ours; the server's error if it sent one. def callback(url: String, +state: String) -> Result<&1, &1, Err, String>: Oauth2.bearer (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=bearer) def bearer(tok: Token, h: Map<&2, List<&2, String>>) -> Map<&2, List<&2, String>>: Oauth2.request (https://jend.leeeet.dev/definition.txt?path=bend-kit-oauth2@0.11.0.1/oauth2.bend&name=request) # Hairpin.request with Authorization: Bearer , over any authorization header in headers. def request(c: Hairpin.Client, tok: Token, +method: String, url: String, headers: Map<&2, List<&2, String>>, body: Bytes.Bytes) -> IO(Hairpin.Client & Result<&1, &1, Hairpin.Err, Http.Res>):