nx_no_cookie_session.nx
buildroot/runtime/hub/nx_no_cookie_session.nx
about
nx_no_cookie_session.nx -- Ed25519-signed short-lived session token.
V-MODAUTH-5 per NISHI_MODERN_AUTH_CHARTER §7. Replaces cookie-
session sessions with a self-contained signed token. Per the
NO-COOKIE / NO-TRACKING CARDINAL (C1 §1): NEVER a cookie.
Token lifecycle:
1. After OPAQUE login succeeds, server calls nx_ncs_mint_token()
with (user_id, realm_id) + short TTL.
2. Server returns base64(token) in JSON body. Client stores in
sessionStorage (NOT localStorage — clears on tab close) OR holds
in CLI process memory.
3. Client sends per-request: `X-Nishi-Session: <base64-token>`.
4. Server calls nx_ncs_validate_token() per protected request.
5. On expiry (~15min), client calls /wiki/admin/refresh-token to
get a new token signed over the same user_id but fresh nonce +
bumped expiry (no passphrase re-prompt).
6. Logout = client discards token. Server stateless; no
invalidation list (per C10 full-privacy: no per-session
server-side correlation). Token bound to short TTL minimizes
leak-window risk.
Token wire format (152 bytes BINARY; ~204 chars base64):
offset 0..32 user_id_hash SHA-256("realm|||user_handle")
offset 32..64 realm_id_hash SHA-256(NxAuthContext.realm_id)
offset 64..72 expires_at_unix big-endian i64 seconds since epoch
offset 72..88 nonce 16 random bytes (CSPRNG)
offset 88..152 ed25519_sig signature over bytes[0..88]
with server's long-term Ed25519 key
SIGNATURE BINDING: server's Ed25519 pubkey is the SOLE authority
here. Token holder = anyone with the right signed bytes within TTL.
We do NOT bind to client cert (deferred V-MODAUTH-2 mTLS path) or
client_pubkey. Short TTL is the leak-window control.
COMPOSES per "avoid duplicate primitives" cardinal:
nx_ed25519_signature ed25519_sign_full + ed25519_verify_full
nx_csprng nonce randomness
sha256 user_id + realm_id hash derivation helpers
dependencies 4 imports · 11 importers
diagram shows first 10 each side; +0 more imports, +1 more importers in the complete lists below.
imports: nx_syscalls.nxnx_csprng.nxnx_ed25519_signature.nxsha256.nx
imported by: nx_account_cleanup.nxnx_hr.nxnx_hr_sov.nxnx_library_gate_handle.nxnx_library_gate_test.nxnx_library_publish.nxnx_library_scholarly.nxnx_modern_auth_flow.nxnx_no_cookie_session_test.nxnx_session_mint_lib.nxnx_wiki_login_flow.nx
structs
| none |
consts
| 69 | const NX_NCS_OK: i64 = 0 |
| 70 | const NX_NCS_BAD_INPUT: i64 = 1340 |
| 71 | const NX_NCS_BUF_OVERFLOW: i64 = 1341 |
| 72 | const NX_NCS_CSPRNG_FAILED: i64 = 1342 |
| 73 | const NX_NCS_SIGN_FAILED: i64 = 1343 |
| 74 | const NX_NCS_VERIFY_FAILED: i64 = 1344 |
| 75 | const NX_NCS_EXPIRED: i64 = 1345 |
| 76 | const NX_NCS_MALFORMED: i64 = 1346 |
| 79 | const NX_NCS_USER_ID_HASH_BYTES: i64 = 32 |
| 80 | const NX_NCS_REALM_ID_HASH_BYTES: i64 = 32 |
| 81 | const NX_NCS_EXPIRES_BYTES: i64 = 8 |
| 82 | const NX_NCS_NONCE_BYTES: i64 = 16 |
| 83 | const NX_NCS_SIG_BYTES: i64 = 64 |
| 84 | const NX_NCS_TOKEN_BYTES: i64 = 152 // 32 + 32 + 8 + 16 + 64 |
| 86 | const NX_NCS_OFF_USER_ID: i64 = 0 |
| 87 | const NX_NCS_OFF_REALM_ID: i64 = 32 |
| 88 | const NX_NCS_OFF_EXPIRES: i64 = 64 |
| 89 | const NX_NCS_OFF_NONCE: i64 = 72 |
| 90 | const NX_NCS_OFF_SIG: i64 = 88 |
| 92 | const NX_NCS_SIGNED_PREFIX_BYTES: i64 = 88 // bytes 0..88 are what's signed |
| 94 | const NX_NCS_DEFAULT_TTL_S: i64 = 900 // 15 minutes per charter §7 |
| 96 | const NX_NCS_MAX_REALM_LEN: i64 = 128 |
| 97 | const NX_NCS_MAX_USER_HANDLE_LEN: i64 = 64 |
functions
| 101 | func _ncs_put_i64_be(out: *u8, v: i64) -> i64 called by 1: nx_ncs_mint_token |
| 113 | func _ncs_get_i64_be(b: *u8) -> i64 called by 1: nx_ncs_validate_token |
| 133 | func nx_ncs_derive_user_id_hash( |
| 162 | func nx_ncs_derive_realm_id_hash( |
| 186 | func nx_ncs_mint_token( |
| 247 | func nx_ncs_validate_token( |
| 306 | func nx_ncs_refresh_token( |