# Token match — `@suaveplan/api-auth-bearer-static` _(no submodules)_ ## Purpose `findTokenIndex` performs a constant-time lookup of a presented bearer token against a fixed table, returning the matching entry's index or `-1` if no entry matches. The function is the security boundary of the package: every other code path in the resolver assumes the match is timing-safe so an attacker cannot binary-search the token table by measuring response latency. The implementation walks every entry, calling `constantTimeEqual` from `@suaveplan/crypto-utils` once per row. The match-tracking variable is written only on the first match; subsequent matches are ignored. Crucially the loop does not break on first match — exiting early would leak the position of the matching token via wall-clock timing. ## Features - Wraps `@suaveplan/crypto-utils` `constantTimeEqual` over UTF-8 byte views. - Iterates the full table for every call — no early exit, no short-circuit on `presented === entry.token`. - Returns the first matching index or `-1`. - Handles `undefined` entries (defensive guard for sparse arrays). ## Usage: Basic ```ts import { findTokenIndex } from "@suaveplan/api-auth-bearer-static/constant-time"; const table = [ { token: "T1" }, { token: "T2" }, ]; const index = findTokenIndex("T2", table); // index === 1 ``` ## Usage: Advanced ```ts import { findTokenIndex } from "@suaveplan/api-auth-bearer-static/constant-time"; interface TokenEntry { readonly token: string; readonly principalId: string; } const table: ReadonlyArray = [ { token: "service-cron", principalId: "p1" }, { token: "service-admin", principalId: "p2" }, ]; function lookup(presented: string): TokenEntry | null { const idx = findTokenIndex(presented, table); return idx === -1 ? null : (table[idx] ?? null); } ``` ## API Reference - `findTokenIndex(presented: string, table: ReadonlyArray<{ token: string }>): number` — returns the index of the first entry whose `token` matches `presented`, or `-1` if no entry matches. ## Implementation Notes `constantTimeEqual` from `@suaveplan/crypto-utils` walks every byte of the two `Uint8Array` views and accumulates differences into an integer via bitwise OR; the function returns whether the accumulator stayed zero. The length-mismatch fast path is documented as not secret (token lengths are not secret in this adapter's threat model — the table is operator-supplied config). The `TextEncoder` round-trip ensures we compare bytes, not surrogate-pair code units; otherwise an attacker could compare a multi- byte presented token against a single-byte entry and learn from the length-mismatch shortcut whether their candidate had the right length.