pkce/lib.rs
1//! This is a minimal library with functions to generate random code verifiers and challenges to be used for OAuth [Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636).
2//!
3//! ```
4//! extern crate pkce;
5//!
6//! fn main() {
7//! let code_verify = pkce::code_verifier(128);
8//! let code_challenge = pkce::code_challenge(&code_verify);
9//!
10//! println!("Code challenge generated: {}", code_challenge);
11//! }
12//! ```
13
14extern crate base64;
15extern crate rand;
16extern crate sha2;
17
18use base64::Engine;
19use rand::{thread_rng, Rng};
20use sha2::{Digest, Sha256};
21
22const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
23 abcdefghijklmnopqrstuvwxyz\
24 0123456789-.~_";
25
26/// Generate a random code verifier.
27///
28/// # Arguments
29///
30/// * `length` - The desired length in bytes of the code verifier. This value should be between 43 and 128 or else the function will panic.
31pub fn code_verifier(length: usize) -> Vec<u8> {
32 assert!(
33 (43..=128).contains(&length),
34 "Code verifier length must be between 43 and 128 bytes"
35 );
36
37 let mut rng = thread_rng();
38
39 (0..length)
40 .map(|_| {
41 let i = rng.gen_range(0..CHARS.len());
42 CHARS[i]
43 })
44 .collect()
45}
46
47fn base64_url_encode(input: &[u8]) -> String {
48 let b64 = base64::engine::general_purpose::STANDARD.encode(input);
49 b64.chars()
50 .filter_map(|c| match c {
51 '=' => None,
52 '+' => Some('-'),
53 '/' => Some('_'),
54 x => Some(x),
55 })
56 .collect()
57}
58
59/// Generate a code challenge from a given code verifier with SHA256 and base64.
60///
61/// # Arguments
62///
63/// * `code_verifier` - The code verifier, such as the one generated by the [`code_verifier`] function.
64pub fn code_challenge(code_verifier: &[u8]) -> String {
65 let mut sha = Sha256::new();
66 sha.update(code_verifier);
67 let result = sha.finalize();
68 base64_url_encode(&result[..])
69}