forked from
slices.network/quickslice
Auto-indexing service and GraphQL API for AT Protocol Records
1/// Secure token generation utilities
2import gleam/bit_array
3import gleam/crypto
4
5/// Generate a secure random authorization code
6pub fn generate_authorization_code() -> String {
7 let random_bytes = crypto.strong_random_bytes(32)
8 bit_array.base64_url_encode(random_bytes, False)
9}
10
11/// Generate a secure random access token
12pub fn generate_access_token() -> String {
13 let random_bytes = crypto.strong_random_bytes(32)
14 bit_array.base64_url_encode(random_bytes, False)
15}
16
17/// Generate a secure random refresh token
18pub fn generate_refresh_token() -> String {
19 let random_bytes = crypto.strong_random_bytes(32)
20 bit_array.base64_url_encode(random_bytes, False)
21}
22
23/// Generate a secure random client ID
24pub fn generate_client_id() -> String {
25 let random_bytes = crypto.strong_random_bytes(16)
26 let encoded = bit_array.base64_url_encode(random_bytes, False)
27 "client_" <> encoded
28}
29
30/// Generate a secure random client secret
31pub fn generate_client_secret() -> String {
32 let random_bytes = crypto.strong_random_bytes(32)
33 bit_array.base64_url_encode(random_bytes, False)
34}
35
36/// Generate a PAR request URI
37pub fn generate_par_request_uri() -> String {
38 let random_bytes = crypto.strong_random_bytes(16)
39 let encoded = bit_array.base64_url_encode(random_bytes, False)
40 "urn:ietf:params:oauth:request_uri:" <> encoded
41}
42
43/// Generate a DPoP nonce
44pub fn generate_dpop_nonce() -> String {
45 let random_bytes = crypto.strong_random_bytes(16)
46 bit_array.base64_url_encode(random_bytes, False)
47}
48
49/// Generate a session ID
50pub fn generate_session_id() -> String {
51 let random_bytes = crypto.strong_random_bytes(16)
52 bit_array.base64_url_encode(random_bytes, False)
53}
54
55/// Generate an OAuth state parameter
56pub fn generate_state() -> String {
57 let random_bytes = crypto.strong_random_bytes(16)
58 bit_array.base64_url_encode(random_bytes, False)
59}
60
61/// Compute JWK thumbprint (JKT) from a signing key
62pub fn compute_jkt(key: String) -> String {
63 let key_bytes = bit_array.from_string(key)
64 let hash = crypto.hash(crypto.Sha256, key_bytes)
65 bit_array.base64_url_encode(hash, False)
66}
67
68/// Get current timestamp (seconds since epoch)
69pub fn current_timestamp() -> Int {
70 get_system_time_native() / 1_000_000_000
71}
72
73/// Calculate expiration timestamp
74pub fn expiration_timestamp(lifetime_seconds: Int) -> Int {
75 current_timestamp() + lifetime_seconds
76}
77
78/// Check if a timestamp is expired
79pub fn is_expired(expires_at: Int) -> Bool {
80 current_timestamp() >= expires_at
81}
82
83@external(erlang, "os", "system_time")
84fn get_system_time_native() -> Int