// Proof Key for Code Exchange (RFC 7636). The client keeps a verifier and sends
// only its SHA-256 digest with the authorization request, so a code stolen from
// the browser's address bar cannot be exchanged on its own.
///|
/// A PKCE pair: `verifier` goes in the token request, `challenge` in the
/// authorization request. Only S256 is used — the plain method protects
/// nothing, and the protocol requires S256 of every client that can do it.
#derive(Debug, Eq)
pub(all) struct Pkce {
verifier : String
challenge : String
}
///|
/// A fresh pair, from 32 bytes of entropy: 43 characters, which is the shortest
/// length RFC 7636 allows and enough to be unguessable.
pub fn Pkce::new() -> Pkce raise Refused {
let bytes = FixedArray::make(32, b'\x00')
let rng = @auto.rng() catch {
_ => raise Refused(message="no entropy to draw a PKCE verifier from")
}
rng.fill(bytes)
Pkce::of(@base64.encode(Bytes::from_array(bytes)[:], kind=Url, padding=false))
}
///|
/// The pair for a verifier already chosen: the challenge is its SHA-256 digest
/// in base64url, without padding.
pub fn Pkce::of(verifier : String) -> Pkce {
let digest = @sha2.hash(@utf8.encode(verifier)[:])
{ verifier, challenge: @base64.encode(digest[:], kind=Url, padding=false), }
}
///|
pub extend Pkce with Debug::{to_repr}
///|
pub extend Pkce with Eq::{not_equal, equal}