Skip to content

docs: correct API URLs, examples, and security claims - #145

Open
CuriousLearner wants to merge 1 commit into
masterfrom
docs/correct-urls-and-examples
Open

docs: correct API URLs, examples, and security claims#145
CuriousLearner wants to merge 1 commit into
masterfrom
docs/correct-urls-and-examples

Conversation

@CuriousLearner

Copy link
Copy Markdown
Owner

Summary

Every documented API URL was wrong in two ways. The router already registers the phone prefix and is created with trailing_slash=False, but the docs told users to mount at api/phone/ and then call /api/phone/register/, which produces a doubled prefix and a trailing slash that does not exist. Verified by resolving against a real URLconf: /phone/register/ raises Resolver404. The mount is now path("api/", include("phone_verify.urls")), giving POST /api/phone/register and POST /api/phone/verify.

docs/integration.rst showed a non-DRF flow calling send_verification() with no arguments and a verify() method the service has never had. It is rewritten around send_security_code_and_generate_session_token() and verify_security_code().

docs/architecture.rst described session tokens as validated JWTs, claiming the signature is checked, that the payload carries iat and exp, and that tampering is therefore prevented. The package only ever calls jwt.encode; there is no jwt.decode anywhere, and the token is used as an opaque database lookup key. The section now describes what actually happens, including that a tampered token fails by matching no row rather than by failing a signature check, and that the token is a bearer value with no independent expiry. The step-1 flow is also reordered, since the record is written before the SMS is sent.

The sandbox recipe in docs/customization.rst told users to override validate_security_code() to return valid unconditionally. That method is where expiry, one-time use, and the brute-force lockout are enforced, so following it silently disabled all three. It now mirrors the shipped backends, which subclass the production backend and override generate_security_code() and _should_bypass_code_check().

The built-in brute-force lockout was absent from every security-facing document, so security.rst and the FAQ still told readers this was entirely their responsibility. It is now documented, framed as per-record protection that does not replace request rate limiting. Likewise the shipped cleanup_phone_verifications command replaces three copies of a hand-rolled retention snippet.

Smaller corrections: examples now set exception_class; redundant send_bulk_sms overrides are dropped now that it is concrete on BaseBackend; a sandbox example using a nonexistent self.options attribute uses self._token; the language parameter is documented; README response bodies match what the API returns; the claim that migrations ship appropriate indexes is corrected, since the only index is the unique constraint whose leading column cannot serve the lookup path; and the security policy's supported-versions table covers the current release.

Test plan

  • URLs verified by resolving all four candidate paths against a real URLconf rather than by reading.
  • Index claim verified against all three migrations with sqlmigrate.
  • Every Python block overlapping the diff extracted and compiled: no failures.
  • Structural lint over all documents: no new warnings, and every added heading underline is full length.
  • Full suite: 144 passed, unchanged, as this touches documentation only.

The router in phone_verify.urls registers the `phone` prefix itself and is
built with `trailing_slash=False`, so the documented mount point and endpoint
URLs were wrong in both directions. Mount at `api/` and drop the trailing
slash: `POST /api/phone/register` and `POST /api/phone/verify`. README response
bodies now match what the viewset actually returns.

Rewrite the non-DRF integration example, which called a `send_verification()`
overload and a `verify()` method that do not exist, around
`send_security_code_and_generate_session_token()` and `verify_security_code()`,
carrying the session token through the Django session. Apply the same fix to the
Celery and OAuth snippets in the FAQ, and correct the sandbox example there to
use `self._token` rather than a nonexistent `options` attribute.

Replace the sandbox recipe in the customization guide. It overrode
`validate_security_code()` to return valid unconditionally, which also discards
the expiry, one-time-use and brute-force checks that live in that method. Custom
backends now subclass their production backend and override
`generate_security_code()` and `_should_bypass_code_check()`, matching the
shipped Twilio and Nexmo backends. Custom backend examples set `exception_class`
and explain what it narrows, and redundant `send_bulk_sms` overrides are dropped
now that the base implementation is concrete.

Correct the architecture guide's session token claims. The package only ever
calls `jwt.encode`; there is no decode, no signature check, and no `iat`/`exp`
in the payload. The token is an opaque bearer value used as a lookup key, and
expiry is governed by the verification record. The step-1 diagram also had the
SMS send before the database write.

Document `MAX_FAILED_ATTEMPTS` in the security guide, FAQ and security policy,
framed as per-record protection that does not replace request rate limiting.
Replace the hand-rolled cleanup snippets with the shipped
`cleanup_phone_verifications` command and `RECORD_RETENTION_DAYS`, add the
`language` parameter to the service signatures in the API reference, correct the
claim that useful indexes ship in the migrations, and refresh the supported
versions table.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant