code wiki / (root) / bearer_auth.nx

bearer_auth.nx source

↩ module page · 127 lines · 4433 B

1// bearer_auth.nx -- extract Bearer tokens from Authorization header. 2// 3// RFC 6750. The modern HTTP auth scheme for OAuth 2.0, JWT, 4// API keys, and general \"the client holds a secret and presents 5// it\" flows. Trivial algorithmically but worth isolating behind 6// a helper so callers don't re-invent the case-insensitive prefix 7// parse + whitespace handling every time. 8// 9// Authorization: Bearer eyJhbGciOi... 10// ^^^^^^ ^^^^^^^^^^^^^ 11// scheme token (opaque to HTTP) 12// 13// The token format itself (JWT / opaque random / signed session) 14// is caller's concern -- we just peel the \"Bearer \" prefix. 15// 16// Invariants: 17// BA1 Scheme match is case-insensitive per RFC 7235 ยง2.1. 18// BA2 Token is returned as (offset, length) into the caller's 19// buffer -- zero-alloc. 20// BA3 Multiple whitespace tolerated between scheme and token 21// (RFC permits 1 or more SP between credentials parts). 22 23import "syscalls.nx" 24 25const BR_ERR_FORMAT: i64 = -1 26const BR_ERR_SHORT: i64 = -2 27 28// ASCII lowercase. 29func br_lower(b: i64) -> i64 { 30 if b >= 0x41 { 31 if b <= 0x5A { return b + 0x20 } 32 } 33 return b 34} 35 36// Match the literal \"bearer\" case-insensitively at offset. 37func br_is_bearer(buf: *u8, off: i64, n: i64) -> i64 { 38 if n < off + 6 { return 0 } 39 if br_lower(buf[off]) != 0x62 { return 0 } // 'b' 40 if br_lower(buf[off + 1]) != 0x65 { return 0 } // 'e' 41 if br_lower(buf[off + 2]) != 0x61 { return 0 } // 'a' 42 if br_lower(buf[off + 3]) != 0x72 { return 0 } // 'r' 43 if br_lower(buf[off + 4]) != 0x65 { return 0 } // 'e' 44 if br_lower(buf[off + 5]) != 0x72 { return 0 } // 'r' 45 return 1 46} 47 48// Extract the Bearer token from an Authorization header VALUE 49// (not the full header; caller strips \"Authorization: \" first). 50// Writes (offset, length) of the token into *tok_off and *tok_len. 51// Returns 0 on success, negative on failure. 52func bearer_auth_extract(hdr: *u8, n: i64, 53 tok_off: *i64, tok_len: *i64) -> i64 { 54 if n < 7 { return BR_ERR_SHORT } 55 if br_is_bearer(hdr, 0, n) != 1 { return BR_ERR_FORMAT } 56 // Must be followed by at least one space. 57 var i: i64 = 6 58 if hdr[i] != 0x20 { return BR_ERR_FORMAT } 59 // Skip run of spaces. 60 while i < n { 61 if hdr[i] != 0x20 { break } 62 i = i + 1 63 } 64 if i >= n { return BR_ERR_FORMAT } 65 66 // Token runs to end-of-input or first whitespace (RFC permits 67 // trailing whitespace / additional fields in some grammars 68 // but for Authorization they're not standard). 69 let start: i64 = i 70 while i < n { 71 if hdr[i] == 0x20 { break } 72 if hdr[i] == 0x09 { break } 73 if hdr[i] == 0x0D { break } 74 if hdr[i] == 0x0A { break } 75 i = i + 1 76 } 77 *tok_off = start 78 *tok_len = i - start 79 return 0 80} 81 82// Convenience: returns 1 if the header starts with \"Bearer\" 83// (case-insensitive) and has at least some token content. 84func bearer_auth_is_present(hdr: *u8, n: i64) -> i64 { 85 let off: *i64 = (sys_mmap(16)) as *i64 86 let len: *i64 = (sys_mmap(16)) as *i64 87 if bearer_auth_extract(hdr, n, off, len) != 0 { return 0 } 88 if *len == 0 { return 0 } 89 return 1 90} 91 92// Compile-only smoke. 93func main() -> i64 { 94 let off: *i64 = (sys_mmap(16)) as *i64 95 let len: *i64 = (sys_mmap(16)) as *i64 96 97 // Happy path. 98 let hdr: *u8 = "Bearer eyJhbGciOiJIUzI1NiJ9" 99 if bearer_auth_extract(hdr, 27, off, len) != 0 { return 1 } 100 if *off != 7 { return 2 } 101 if *len != 20 { return 3 } 102 if hdr[*off] != 0x65 { return 4 } // 'e' 103 104 // Lowercase scheme. 105 let hdr2: *u8 = "bearer abc" 106 if bearer_auth_extract(hdr2, 10, off, len) != 0 { return 5 } 107 if *off != 7 { return 6 } 108 if *len != 3 { return 7 } 109 110 // Multiple spaces between scheme and token. 111 let hdr3: *u8 = "Bearer xyz" 112 if bearer_auth_extract(hdr3, 12, off, len) != 0 { return 8 } 113 if *off != 9 { return 9 } 114 if *len != 3 { return 10 } 115 116 // Wrong scheme -> error. 117 let hdr4: *u8 = "Basic dXNlcjpwYXNz" 118 if bearer_auth_extract(hdr4, 18, off, len) != BR_ERR_FORMAT { 119 return 11 120 } 121 122 // Presence helper. 123 if bearer_auth_is_present(hdr, 27) != 1 { return 12 } 124 if bearer_auth_is_present(hdr4, 18) != 0 { return 13 } 125 126 return 0 127}