nx_bearer_auth.nx source
↩ module page · 133 lines · 4560 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
23// nx_safety_envelope:
24// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
25// sil_target: SIL1
26// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
27// verdict: NOT_YET_EVALUATED
28
29import "nx_syscalls.nx"
30
31const BR_ERR_FORMAT: i64 = -1
32const BR_ERR_SHORT: i64 = -2
33
34// ASCII lowercase.
35func br_lower(b: i64) -> i64 {
36 if b >= 0x41 {
37 if b <= 0x5A { return b + 0x20 }
38 }
39 return b
40}
41
42// Match the literal \"bearer\" case-insensitively at offset.
43func br_is_bearer(buf: *u8, off: i64, n: i64) -> i64 {
44 if n < off + 6 { return 0 }
45 if br_lower(buf[off]) != 0x62 { return 0 } // 'b'
46 if br_lower(buf[off + 1]) != 0x65 { return 0 } // 'e'
47 if br_lower(buf[off + 2]) != 0x61 { return 0 } // 'a'
48 if br_lower(buf[off + 3]) != 0x72 { return 0 } // 'r'
49 if br_lower(buf[off + 4]) != 0x65 { return 0 } // 'e'
50 if br_lower(buf[off + 5]) != 0x72 { return 0 } // 'r'
51 return 1
52}
53
54// Extract the Bearer token from an Authorization header VALUE
55// (not the full header; caller strips \"Authorization: \" first).
56// Writes (offset, length) of the token into *tok_off and *tok_len.
57// Returns 0 on success, negative on failure.
58func bearer_auth_extract(hdr: *u8, n: i64,
59 tok_off: *i64, tok_len: *i64) -> i64 {
60 if n < 7 { return BR_ERR_SHORT }
61 if br_is_bearer(hdr, 0, n) != 1 { return BR_ERR_FORMAT }
62 // Must be followed by at least one space.
63 var i: i64 = 6
64 if hdr[i] != 0x20 { return BR_ERR_FORMAT }
65 // Skip run of spaces.
66 while i < n {
67 if hdr[i] != 0x20 { break }
68 i = i + 1
69 }
70 if i >= n { return BR_ERR_FORMAT }
71
72 // Token runs to end-of-input or first whitespace (RFC permits
73 // trailing whitespace / additional fields in some grammars
74 // but for Authorization they're not standard).
75 let start: i64 = i
76 while i < n {
77 if hdr[i] == 0x20 { break }
78 if hdr[i] == 0x09 { break }
79 if hdr[i] == 0x0D { break }
80 if hdr[i] == 0x0A { break }
81 i = i + 1
82 }
83 *tok_off = start
84 *tok_len = i - start
85 return 0
86}
87
88// Convenience: returns 1 if the header starts with \"Bearer\"
89// (case-insensitive) and has at least some token content.
90func bearer_auth_is_present(hdr: *u8, n: i64) -> i64 {
91 let off: *i64 = (sys_mmap(16)) as *i64
92 let len: *i64 = (sys_mmap(16)) as *i64
93 if bearer_auth_extract(hdr, n, off, len) != 0 { return 0 }
94 if *len == 0 { return 0 }
95 return 1
96}
97
98// Compile-only smoke.
99func main() -> i64 {
100 let off: *i64 = (sys_mmap(16)) as *i64
101 let len: *i64 = (sys_mmap(16)) as *i64
102
103 // Happy path.
104 let hdr: *u8 = "Bearer eyJhbGciOiJIUzI1NiJ9"
105 if bearer_auth_extract(hdr, 27, off, len) != 0 { return 1 }
106 if *off != 7 { return 2 }
107 if *len != 20 { return 3 }
108 if hdr[*off] != 0x65 { return 4 } // 'e'
109
110 // Lowercase scheme.
111 let hdr2: *u8 = "bearer abc"
112 if bearer_auth_extract(hdr2, 10, off, len) != 0 { return 5 }
113 if *off != 7 { return 6 }
114 if *len != 3 { return 7 }
115
116 // Multiple spaces between scheme and token.
117 let hdr3: *u8 = "Bearer xyz"
118 if bearer_auth_extract(hdr3, 12, off, len) != 0 { return 8 }
119 if *off != 9 { return 9 }
120 if *len != 3 { return 10 }
121
122 // Wrong scheme -> error.
123 let hdr4: *u8 = "Basic dXNlcjpwYXNz"
124 if bearer_auth_extract(hdr4, 18, off, len) != BR_ERR_FORMAT {
125 return 11
126 }
127
128 // Presence helper.
129 if bearer_auth_is_present(hdr, 27) != 1 { return 12 }
130 if bearer_auth_is_present(hdr4, 18) != 0 { return 13 }
131
132 return 0
133}