v0.14 is out: a mobile auth pack for Swift/iOS and Android, catching insecure token storage, cleartext traffic, and OAuth in embedded WebViews. Read more →
HIGH AI PREVALENCE: MEDIUM auth.py.oauth.insecure-token-endpoint

An OAuth/OIDC endpoint is being contacted over cleartext http://.

Why AI tools produce this: AI coding tools produce this regularly, typically when prompted for a shortcut or a quick fix.

Why this matters

Authorization codes, client_secret, access/refresh tokens, and the code_verifier then travel unencrypted: a network attacker can read or rewrite them and take over the flow.

RFC 6749 §3.1 / §10.9 require TLS for the authorization and token endpoints. Use https:// for every authorize, token, userinfo, and .well-known discovery URL. http://localhost and loopback addresses are fine for local development and are not flagged.

VULNERABLE
vulnerable.py
"""OAuth/OIDC endpoints contacted over cleartext http://."""

import requests

# ruleid: auth.py.oauth.insecure-token-endpoint
TOKEN_URL = "http://idp.example.com/oauth/token"

# ruleid: auth.py.oauth.insecure-token-endpoint
AUTHORIZE_URL = "http://idp.example.com/authorize?response_type=code&client_id=abc123"

# ruleid: auth.py.oauth.insecure-token-endpoint
CONNECT_TOKEN = "http://login.example.com/connect/token"

# ruleid: auth.py.oauth.insecure-token-endpoint
DISCOVERY = "http://idp.example.com/.well-known/openid-configuration"


def fetch_token(code: str):
    # ruleid: auth.py.oauth.insecure-token-endpoint
    return requests.post("http://auth.example.com/oauth2/token", data={"grant_type": "authorization_code", "code": code})
SAFE
safe.py
"""OAuth/OIDC endpoints over TLS, plus loopback dev hosts that are exempt."""

import requests

# ok: auth.py.oauth.insecure-token-endpoint -- TLS, the requirement
TOKEN_URL = "https://idp.example.com/oauth/token"

# ok: auth.py.oauth.insecure-token-endpoint -- TLS authorize endpoint
AUTHORIZE_URL = "https://idp.example.com/authorize?response_type=code&client_id=abc123"

# ok: auth.py.oauth.insecure-token-endpoint -- localhost dev host is exempt
LOCAL_TOKEN = "http://localhost:8080/oauth/token"

# ok: auth.py.oauth.insecure-token-endpoint -- loopback dev host is exempt
LOOPBACK = "http://127.0.0.1:9000/connect/token"

# ok: auth.py.oauth.insecure-token-endpoint -- plain http URL with no OAuth marker
HEALTHCHECK = "http://idp.example.com/healthz"


def fetch_token(code: str):
    # ok: auth.py.oauth.insecure-token-endpoint -- TLS token exchange
    return requests.post(TOKEN_URL, data={"grant_type": "authorization_code", "code": code})

Suppressing this rule

If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.

# oauthlint-disable-next-line auth.py.oauth.insecure-token-endpoint -- <reason>

References

https://datatracker.ietf.org/doc/html/rfc6749#section-3.1 ↗https://datatracker.ietf.org/doc/html/rfc6749#section-10.9 ↗https://cwe.mitre.org/data/definitions/319.html ↗