Files
2026-05-27 23:29:53 +01:00

2.7 KiB

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

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

import { findTokenIndex } from "@suaveplan/api-auth-bearer-static/constant-time";

interface TokenEntry {
    readonly token: string;
    readonly principalId: string;
}

const table: ReadonlyArray<TokenEntry> = [
    { 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.