firebase_rs_sdk/auth/oauth/
pkce.rs1use base64::Engine;
2use rand::Rng;
3use sha2::{Digest, Sha256};
4
5const PKCE_LENGTH: usize = 64;
6const PKCE_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
7
8#[derive(Debug, Clone)]
10pub struct PkcePair {
11 code_verifier: String,
12 code_challenge: String,
13}
14
15impl PkcePair {
16 pub fn generate() -> Self {
18 let mut rng = rand::thread_rng();
19 let verifier: String = (0..PKCE_LENGTH)
20 .map(|_| {
21 let idx = rng.gen_range(0..PKCE_CHARSET.len());
22 PKCE_CHARSET[idx] as char
23 })
24 .collect();
25
26 let digest = Sha256::digest(verifier.as_bytes());
27 let challenge = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(digest);
28
29 Self {
30 code_verifier: verifier,
31 code_challenge: challenge,
32 }
33 }
34
35 pub fn code_verifier(&self) -> &str {
37 &self.code_verifier
38 }
39
40 pub fn code_challenge(&self) -> &str {
42 &self.code_challenge
43 }
44
45 pub fn method(&self) -> &'static str {
47 "S256"
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn pkce_pair_has_expected_lengths() {
57 let pkce = PkcePair::generate();
58 assert!(pkce.code_verifier().len() >= 43);
59 assert!(pkce.code_verifier().len() <= 128);
60 assert!(!pkce.code_challenge().is_empty());
61 assert_eq!(pkce.method(), "S256");
62 }
63}