Skip to main content

stynx_code_auth/infrastructure/oauth/
pkce.rs

1use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
2use sha2::{Digest, Sha256};
3
4pub struct PkceChallenge {
5    pub code_verifier: String,
6    pub code_challenge: String,
7}
8
9pub fn generate_pkce() -> PkceChallenge {
10    let verifier_bytes = generate_random_bytes();
11    let code_verifier = URL_SAFE_NO_PAD.encode(&verifier_bytes);
12
13    let mut hasher = Sha256::new();
14    hasher.update(code_verifier.as_bytes());
15    let hash = hasher.finalize();
16    let code_challenge = URL_SAFE_NO_PAD.encode(hash);
17
18    PkceChallenge {
19        code_verifier,
20        code_challenge,
21    }
22}
23
24fn generate_random_bytes() -> [u8; 32] {
25    use std::collections::hash_map::DefaultHasher;
26    use std::hash::{Hash, Hasher};
27    use std::time::{SystemTime, UNIX_EPOCH};
28
29    let mut bytes = [0u8; 32];
30    let now = SystemTime::now()
31        .duration_since(UNIX_EPOCH)
32        .unwrap_or_default()
33        .as_nanos();
34    let pid = std::process::id();
35
36    for (i, byte) in bytes.iter_mut().enumerate() {
37        let mut hasher = DefaultHasher::new();
38        now.hash(&mut hasher);
39        pid.hash(&mut hasher);
40        i.hash(&mut hasher);
41        (now ^ (pid as u128) ^ (i as u128)).hash(&mut hasher);
42        *byte = (hasher.finish() & 0xff) as u8;
43    }
44    bytes
45}