Skip to content

auth.jwt.in-url

A JWT-looking value (header eyJ…) appears in a URL query string

OAuthLint idAUTH-JWT-008
SeverityERROR
LLM prevalenceMEDIUM
CWECWE-598
OWASPAPI1:2023
Languagesjavascript, typescript

Why this matters

A JWT-looking value (header eyJ…) appears in a URL query string or fragment. URLs leak into server logs, browser history, the Referer header (sent to every third-party CDN, ad pixel, and analytics script on the destination page), and even copy-paste operations. A JWT in a URL is a leaked JWT.

Send JWTs in the Authorization: Bearer … header, or in a Secure; HttpOnly; SameSite cookie. Never in the URL.

OWASP ASVS V3.2.3 explicitly forbids credentials in URL parameters.

❌ Vulnerable

ts
// ruleid: auth.jwt.in-url
export const downloadLink =
  'https://api.example.com/files/123?token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.abc';

// ruleid: auth.jwt.in-url
export const magicLink =
  'https://app.example.com/auth/magic?jwt=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiZm9vIn0.xyz';

// ruleid: auth.jwt.in-url
export const fragmentLink =
  'https://app.example.com/dashboard#access_token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.zzz';

// ruleid: auth.jwt.in-url -- JWT in a path segment
export const pathLink =
  'https://app.example.com/verify/eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiZm9vIn0.qqq';

✅ Safe

ts
// ok: auth.jwt.in-url
export const goodLink = 'https://app.example.com/dashboard';

// ok: auth.jwt.in-url -- a non-JWT base64 redirect param, not a token
export const redirectLink = 'https://app.example.com/login?next=aHR0cHM6Ly9hcHAvaG9tZQ';

// ok: auth.jwt.in-url -- token in Authorization header, not URL
export function fetchWithToken(token: string) {
  return fetch('https://api.example.com/files/123', {
    headers: { Authorization: `Bearer ${token}` },
  });
}

Suppressing this rule (when you really must)

ts
// oauthlint-disable-next-line auth.jwt.in-url -- <reason>
thisLineWouldOtherwiseTriggerTheRule();

Disable directives are line-scoped by design — wholesale silencing of a rule across the codebase is intentionally not supported, because the next reviewer needs to see exactly which lines opted out.

References

Released under the MIT License · powered by Semgrep