Skip to content

make handle selection on signup optional (issue #22) - #29

Merged
aspiers merged 10 commits into
mainfrom
22-make-handle-selection-on-signup-optional
Mar 24, 2026
Merged

make handle selection on signup optional (issue #22)#29
aspiers merged 10 commits into
mainfrom
22-make-handle-selection-on-signup-optional

Conversation

@Kzoeps

@Kzoeps Kzoeps commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds HANDLE_SELECTION_MODE env var to control whether users can choose their handle during signup
  • Supports user-choice, random, and none modes, with fallback precedence chain
  • Fixes premature auth_flow cleanup and step label issues in random-mode flow

Closes #22

Also closes HYPER-192 on linear

Summary by CodeRabbit

  • New Features

    • Multiple signup handle modes: random, picker, picker-with-random.
    • Random signup skips the picker and proceeds directly; picker-with-random shows a "Generate random handle" button with availability checks, retries, and timeouts; button is disabled during submission.
  • Tests

    • Expanded coverage for handle-mode resolution, persistence, client-metadata fallback, PAR ping, and callback signature contract.
  • Documentation

    • Updated env example with EPDS_DEFAULT_HANDLE_MODE and session-secret guidance.

@vercel

vercel Bot commented Mar 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
epds-demo Ready Ready Preview, Comment Mar 24, 2026 4:53am

Request Review

@coderabbitai

coderabbitai Bot commented Mar 17, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 94b0d72e-8b4c-46b7-af70-724901757725

📥 Commits

Reviewing files that changed from the base of the PR and between ededb3a and bd3655b.

📒 Files selected for processing (16)
  • .beads/issues.jsonl
  • .env.example
  • packages/auth-service/.env.example
  • packages/auth-service/src/__tests__/login-page.test.ts
  • packages/auth-service/src/__tests__/ping-par-request.test.ts
  • packages/auth-service/src/lib/client-metadata.ts
  • packages/auth-service/src/lib/ping-par-request.ts
  • packages/auth-service/src/routes/choose-handle.ts
  • packages/auth-service/src/routes/complete.ts
  • packages/auth-service/src/routes/login-page.ts
  • packages/auth-service/src/routes/recovery.ts
  • packages/pds-core/src/index.ts
  • packages/shared/src/__tests__/crypto.test.ts
  • packages/shared/src/db.ts
  • packages/shared/src/handle.ts
  • packages/shared/src/index.ts

📝 Walkthrough

Walkthrough

Adds per-request / per-client / server-default handle-assignment modes (random | picker | picker-with-random), persists handleMode on auth flows, resolves mode by precedence (query → client metadata → env), and updates login, choose-handle, complete flows, DB schema, shared types, client-metadata shape, ping-par, and tests.

Changes

Cohort / File(s) Summary
Configuration
\.env.example, packages/auth-service/.env.example
Documented EPDS_DEFAULT_HANDLE_MODE and added guidance for generating AUTH_SESSION_SECRET (openssl rand -hex 32).
Shared handle types & exports
packages/shared/src/handle.ts, packages/shared/src/index.ts
Added VALID_HANDLE_MODES and exported HandleMode type; re-exported VALID_HANDLE_MODES from shared index.
DB schema & persistence
packages/shared/src/db.ts
Added nullable auth_flow.handle_mode column, updated migration, added AuthFlowRow.handleMode, and persisted/returned handleMode in create/get methods.
Client metadata shape
packages/auth-service/src/lib/client-metadata.ts
Extended ClientMetadata with optional epds_handle_mode?: HandleMode (documented allowed values).
Login flow & mode resolution
packages/auth-service/src/routes/login-page.ts, packages/auth-service/src/__tests__/login-page.test.ts
Added safeResolveClientMetadata() and resolveHandleMode(); derive handleMode (query → clientMeta → env); store handleMode in createAuthFlow; added tests for resolution and persistence.
Choose-handle UI & client logic
packages/auth-service/src/routes/choose-handle.ts
Threaded flow.handleMode through handlers; short-circuited GET/POST when random; added showRandomButton for picker-with-random; introduced client-side random-handle generation with availability checks, retries, and timeouts; unified PAR ping via pingParRequest.
Completion branching & contract
packages/auth-service/src/routes/complete.ts, packages/pds-core/src/index.ts
complete now branches on handleMode: random skips chooser and redirects callback without handle (PDS assigns); added non-fatal pingParRequest and explicit CONTRACT JSDoc in PDS core about missing handle.
Ping PAR helper & tests
packages/auth-service/src/lib/ping-par-request.ts, packages/auth-service/src/__tests__/ping-par-request.test.ts
Added pingParRequest() with a 3s timeout, non-throwing result shape, and tests validating HTTP statuses, errors, header/query encoding, and timeout behavior.
Crypto contract test
packages/shared/src/__tests__/crypto.test.ts
Added test ensuring sign/verify semantics tolerate omitted vs undefined handle per random-mode contract.
Minor comments
packages/auth-service/src/routes/recovery.ts
Comment added noting handleMode intentionally omitted for recovery flows.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client App
    participant AuthSvc as Auth Service
    participant MetaSvc as Client Metadata<br/>(fetch)
    participant DB as Database
    participant PDS as PDS Core

    Client->>AuthSvc: GET /oauth/authorize\n(client_id, optional epds_handle_mode)
    activate AuthSvc
    AuthSvc->>MetaSvc: safeResolveClientMetadata(client_id)
    activate MetaSvc
    MetaSvc-->>AuthSvc: ClientMetadata or {}
    deactivate MetaSvc
    AuthSvc->>AuthSvc: resolveHandleMode(query, clientMeta, env)
    AuthSvc->>DB: createAuthFlow(..., handleMode)
    activate DB
    DB-->>AuthSvc: created auth_flow
    deactivate DB
    AuthSvc-->>Client: Redirect to /auth/login
    deactivate AuthSvc

    Client->>AuthSvc: Complete auth flow (OTP)
    activate AuthSvc
    AuthSvc->>DB: getAuthFlow(flowId) -> includes handleMode
    activate DB
    DB-->>AuthSvc: auth_flow (handleMode)
    deactivate DB
    alt handleMode == "random"
        AuthSvc->>PDS: pingParRequest(flow.requestUri) (non-fatal)
        AuthSvc->>PDS: Redirect epds-callback (no handle param)
        Note over PDS: PDS assigns random handle
    else handleMode == "picker" or "picker-with-random"
        AuthSvc-->>Client: Redirect to /auth/choose-handle
        Note over Client: UI shows random button only for picker-with-random
    end
    deactivate AuthSvc
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰
I hopped through env, tests, and flow,
Three modes to pick — fast, or slow.
Query, metadata, env decide the song,
Random skips, pickers linger long.
A nibble, a hop — signup paths belong.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: making handle selection on signup optional (supporting multiple modes) and references the linked issue #22.
Linked Issues check ✅ Passed The PR implements all core requirements: three handle modes (random/picker/picker-with-random), precedence chain (query param → client metadata → env var), persistence in auth_flow table, conditional UI rendering, and random handle generation.
Out of Scope Changes check ✅ Passed All changes directly support the handle mode feature: environment variables, type definitions, database schema, route handlers, tests, and helper functions. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 22-make-handle-selection-on-signup-optional

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Kzoeps
Kzoeps force-pushed the 22-make-handle-selection-on-signup-optional branch from a5bd43a to dfcd63a Compare March 17, 2026 09:06
@coveralls-official

coveralls-official Bot commented Mar 17, 2026

Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 23473716758

Details

  • 15 of 47 (31.91%) changed or added relevant lines in 6 files are covered.
  • 3 unchanged lines in 2 files lost coverage.
  • Overall coverage increased (+0.7%) to 29.458%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packages/auth-service/src/routes/login-page.ts 7 11 63.64%
packages/auth-service/src/routes/complete.ts 0 11 0.0%
packages/auth-service/src/routes/choose-handle.ts 0 17 0.0%
Files with Coverage Reduction New Missed Lines %
packages/auth-service/src/routes/choose-handle.ts 1 0.0%
packages/auth-service/src/routes/login-page.ts 2 12.6%
Totals Coverage Status
Change from base Build 23420457847: 0.7%
Covered Lines: 515
Relevant Lines: 1636

💛 - Coveralls

@Kzoeps

Kzoeps commented Mar 17, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review please

@coderabbitai

coderabbitai Bot commented Mar 17, 2026

Copy link
Copy Markdown

@Kzoeps Sure, I'll kick off a review of this PR right away!

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
.env.example (1)

77-80: Consider reordering the new PDS_* keys to clear dotenv-linter warnings.

The current order in this block still triggers UnorderedKey warnings; sorting these entries to the repository’s expected order will keep env lint output clean.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env.example around lines 77 - 80, Reorder the newly added environment keys
so they follow the repository's expected alphabetical/order convention to avoid
dotenv-linter UnorderedKey warnings: locate the PDS_* entries (PDS_DID_PLC_URL,
PDS_BSKY_APP_VIEW_URL, PDS_BSKY_APP_VIEW_DID, PDS_CRAWLERS) in .env.example and
sort them into the same order used elsewhere in the repo (e.g., alphabetically
or matching adjacent blocks), then save the file so dotenv-linter no longer
flags UnorderedKey for these PDS_* variables.
packages/auth-service/src/routes/complete.ts (1)

106-140: Consider aligning auth_flow cleanup with the 5d (existing user, no consent) path for consistency.

The random-mode path currently relies on database TTL to expire the auth_flow row (as noted in the code comment at line 144), whereas the 5d path explicitly deletes it at lines 175-176. Since pds-core has no error-handling path that redirects back to auth-service for random-mode failures (it retries internally and renders an error page if all attempts fail), there is no need to keep the auth_flow row alive after the redirect.

Explicit deletion would be more consistent with the 5d path and clearer in intent, even though TTL cleanup eventually handles expiry.

♻️ Suggested cleanup for random-mode path
         const params = new URLSearchParams({ ...callbackParams, ts, sig })
         logger.info(
           { email, flowId },
           'New user (random mode): skipping handle picker, redirecting to epds-callback',
         )
+        // Cleanup: remove auth_flow row and cookie (no retry needed for random mode)
+        ctx.db.deleteAuthFlow(flowId)
+        res.clearCookie(AUTH_FLOW_COOKIE)
         res.redirect(
           303,
           `${ctx.config.pdsPublicUrl}/oauth/epds-callback?${params.toString()}`,
         )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/auth-service/src/routes/complete.ts` around lines 106 - 140, The
random-mode branch (when flow.handleMode === 'random') currently redirects to
epds-callback without removing the auth_flow row; add the same explicit deletion
used in the 5d (existing user, no consent) path so the auth_flow record for
flowId is removed before calling res.redirect. Locate the deletion logic used in
the 5d path (the function or ORM call that deletes the auth_flow row), and
invoke that same deletion (using flowId/flow) immediately before constructing
the callback params and calling res.redirect so behavior is consistent with the
other path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.env.example:
- Around line 77-80: Reorder the newly added environment keys so they follow the
repository's expected alphabetical/order convention to avoid dotenv-linter
UnorderedKey warnings: locate the PDS_* entries (PDS_DID_PLC_URL,
PDS_BSKY_APP_VIEW_URL, PDS_BSKY_APP_VIEW_DID, PDS_CRAWLERS) in .env.example and
sort them into the same order used elsewhere in the repo (e.g., alphabetically
or matching adjacent blocks), then save the file so dotenv-linter no longer
flags UnorderedKey for these PDS_* variables.

In `@packages/auth-service/src/routes/complete.ts`:
- Around line 106-140: The random-mode branch (when flow.handleMode ===
'random') currently redirects to epds-callback without removing the auth_flow
row; add the same explicit deletion used in the 5d (existing user, no consent)
path so the auth_flow record for flowId is removed before calling res.redirect.
Locate the deletion logic used in the 5d path (the function or ORM call that
deletes the auth_flow row), and invoke that same deletion (using flowId/flow)
immediately before constructing the callback params and calling res.redirect so
behavior is consistent with the other path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0d747390-4291-41b1-a443-985174564186

📥 Commits

Reviewing files that changed from the base of the PR and between ad7fd26 and dfcd63a.

📒 Files selected for processing (14)
  • .beads/issues.jsonl
  • .env.example
  • packages/auth-service/.env.example
  • packages/auth-service/src/__tests__/login-page.test.ts
  • packages/auth-service/src/lib/client-metadata.ts
  • packages/auth-service/src/routes/choose-handle.ts
  • packages/auth-service/src/routes/complete.ts
  • packages/auth-service/src/routes/login-page.ts
  • packages/auth-service/src/routes/recovery.ts
  • packages/pds-core/src/index.ts
  • packages/shared/src/__tests__/crypto.test.ts
  • packages/shared/src/db.ts
  • packages/shared/src/handle.ts
  • packages/shared/src/index.ts

@Kzoeps
Kzoeps force-pushed the 22-make-handle-selection-on-signup-optional branch from dfcd63a to ba7109c Compare March 17, 2026 10:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/auth-service/src/routes/choose-handle.ts`:
- Around line 592-626: tryRandomHandle currently applies availability results
regardless of whether the user has changed the input, so stale fetches can
overwrite newer state; fix by recording the random handle you requested (e.g.
set a module-level pendingRandomHandle = local or a per-call token immediately
after computing local in tryRandomHandle) and before changing isAvailable,
setStatus, or updating UI in the fetch.then/ catch handlers verify that
pendingRandomHandle still equals local (or the token matches); only apply
updates when it matches and clear pendingRandomHandle when done; this keeps
tryRandomHandle, randomLocalPart, input, isAvailable and updateSubmit logic
intact while preventing stale updates.
- Around line 176-186: The route currently only special-cases
'picker-with-random' and therefore allows users in a flow with
result.flow.handleMode === 'random' to still pick a custom handle; add an
explicit guard in the /auth/choose-handle handlers to reject flows where
flow.handleMode === 'random' (check result.flow.handleMode or
res.locals.flow.handleMode depending on where flow is read) and return an error
response (e.g., res.status(400).send or render an error page) instead of calling
renderChooseHandlePage or allowing signing; apply the same guard to the other
handler that renders/handles the choose-handle page (the second occurrence
around the other call site that also computes showRandomButton) so 'random'
flows cannot proceed.

In `@packages/auth-service/src/routes/login-page.ts`:
- Around line 92-96: The handler currently calls resolveHandleMode only with
req.query.epds_handle_mode and clientMeta, so epds_handle_mode supplied via PAR
is ignored; update the call to prefer the epds_handle_mode from the pushed
authorization request when present (fall back to req.query and then to
clientMeta/env) before persisting to auth_flow. Specifically, when computing
handleMode (the resolveHandleMode call that uses req.query.epds_handle_mode and
clientMeta), also extract epds_handle_mode from the parsed PAR payload (the code
path that later reads login_hint from the pushed request) and pass that value
into resolveHandleMode so clients that provide epds_handle_mode only in PAR are
handled correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 427a1ce3-028f-4b12-a67a-286a4184e6fb

📥 Commits

Reviewing files that changed from the base of the PR and between dfcd63a and ba7109c.

📒 Files selected for processing (7)
  • .beads/issues.jsonl
  • .env.example
  • packages/auth-service/src/__tests__/login-page.test.ts
  • packages/auth-service/src/lib/client-metadata.ts
  • packages/auth-service/src/routes/choose-handle.ts
  • packages/auth-service/src/routes/login-page.ts
  • packages/pds-core/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/auth-service/src/tests/login-page.test.ts

Comment thread packages/auth-service/src/routes/choose-handle.ts
Comment thread packages/auth-service/src/routes/choose-handle.ts
Comment thread packages/auth-service/src/routes/login-page.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/pds-core/src/index.ts`:
- Around line 245-251: The JSDoc `@see` reference in the CONTRACT block is using
an incorrect relative path; update the first `@see` from
../../../auth-service/src/routes/complete.ts to
../../auth-service/src/routes/complete.ts so it correctly points from the
pds-core/src directory to packages/auth-service/src/routes/complete.ts — look
for the CONTRACT JSDoc block (the comment referencing absent `handle` param /
handleMode='random') and update the `@see` link accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 59d3a2cd-c934-489e-a584-41fce630c00b

📥 Commits

Reviewing files that changed from the base of the PR and between ba7109c and cb70d19.

📒 Files selected for processing (14)
  • .beads/issues.jsonl
  • .env.example
  • packages/auth-service/.env.example
  • packages/auth-service/src/__tests__/login-page.test.ts
  • packages/auth-service/src/lib/client-metadata.ts
  • packages/auth-service/src/routes/choose-handle.ts
  • packages/auth-service/src/routes/complete.ts
  • packages/auth-service/src/routes/login-page.ts
  • packages/auth-service/src/routes/recovery.ts
  • packages/pds-core/src/index.ts
  • packages/shared/src/__tests__/crypto.test.ts
  • packages/shared/src/db.ts
  • packages/shared/src/handle.ts
  • packages/shared/src/index.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/auth-service/src/routes/recovery.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/auth-service/src/tests/login-page.test.ts
  • packages/shared/src/index.ts
  • packages/auth-service/src/lib/client-metadata.ts
  • packages/shared/src/handle.ts
  • packages/shared/src/tests/crypto.test.ts

Comment thread packages/pds-core/src/index.ts
@Kzoeps
Kzoeps force-pushed the 22-make-handle-selection-on-signup-optional branch from cb70d19 to cc5655a Compare March 17, 2026 11:08
@Kzoeps Kzoeps self-assigned this Mar 18, 2026
Kzoeps added 6 commits March 23, 2026 11:03
- Export resolveHandleMode and safeResolveClientMetadata for testability
- Add 8 tests for resolveHandleMode covering all precedence levels
- Add 4 tests for safeResolveClientMetadata covering error paths
- All tests pass (298 total)

Addresses Coveralls coverage reduction in login-page.ts
@Kzoeps
Kzoeps force-pushed the 22-make-handle-selection-on-signup-optional branch from cc5655a to 7267ad0 Compare March 23, 2026 05:04
@railway-app
railway-app Bot temporarily deployed to e2e-test-pds / production March 24, 2026 03:46 Inactive
@aspiers aspiers changed the title 22 make handle selection on signup optional make handle selection on signup optional (issue #22) Mar 24, 2026
- Extract makeDb/closeDb helpers to share DB setup/teardown between
  the two describe blocks that were copy-pasting beforeEach/afterEach
- Collapse the four identical handle-mode storage tests into it.each
- Extract withEnv() helper to eliminate repeated origEnv save/restore
  boilerplate across six resolveHandleMode tests
The function is inlined in a server-rendered template literal and has no
access to the server-side module system, making the duplication unavoidable.
@railway-app
railway-app Bot temporarily deployed to e2e-test-pds / production March 24, 2026 04:52 Inactive
@sonarqubecloud

Copy link
Copy Markdown

@aspiers
aspiers merged commit 6f7c01f into main Mar 24, 2026
10 checks passed
@aspiers
aspiers deleted the 22-make-handle-selection-on-signup-optional branch March 24, 2026 05:04
@aspiers

aspiers commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai Update the summary to include how a trusted client app can change the handle selection mode.

@coderabbitai

coderabbitai Bot commented Mar 25, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
cat packages/auth-service/src/lib/client-metadata.ts
echo "---"
cat packages/auth-service/src/routes/login-page.ts

Length of output: 25706


@aspiers Here's the mechanism for how a trusted client app can change the handle selection mode, which I'll include in the regenerated summary:

A client app sets epds_handle_mode directly in its OAuth client metadata JSON document (the file hosted at the client_id URL, per ATProto convention). When a user authenticates via that client, the auth-service fetches and caches this metadata (via safeResolveClientMetadata), then feeds clientMeta.epds_handle_mode into resolveHandleMode(), which applies the following precedence:

  1. Per-request query param epds_handle_mode (highest — operator/debug override)
  2. Client metadata epds_handle_mode in the app's client-metadata.json ← trusted client app control
  3. Deployment env var EPDS_DEFAULT_HANDLE_MODE
  4. null fallback (which defaults to picker behaviour)

Valid values at every level are random, picker, and picker-with-random. Invalid values are silently skipped and resolution falls through to the next source. The resolved mode is stored on the auth_flow row and governs the rest of the signup flow.

I'll now regenerate the PR summary with this included.

Please include in the summary how a trusted client app can change the handle selection mode: by adding an epds_handle_mode field (random | picker | picker-with-random) to its OAuth client metadata JSON (hosted at the client_id URL). The auth-service fetches and caches this metadata via safeResolveClientMetadata, then resolveHandleMode applies a precedence chain: per-request query param → client metadata epds_handle_mode → deployment env var EPDS_DEFAULT_HANDLE_MODEnull fallback. Invalid values at any level are silently skipped and resolution falls through to the next source.


🧠 Learnings used
Learnt from: Kzoeps
Repo: hypercerts-org/ePDS PR: 29
File: packages/auth-service/src/routes/login-page.ts:92-96
Timestamp: 2026-03-17T10:17:43.948Z
Learning: In `packages/auth-service/src/routes/login-page.ts` (hypercerts-org/ePDS): `epds_handle_mode` is delivered only via query parameter (`req.query.epds_handle_mode`), never via the Pushed Authorization Request (PAR) body. Do not flag missing PAR extraction for this parameter — clients do not send it via PAR. The issue `#22` spec mention of PAR as a delivery channel is not implemented.

Learnt from: Kzoeps
Repo: hypercerts-org/ePDS PR: 29
File: packages/auth-service/src/routes/login-page.ts:92-96
Timestamp: 2026-03-17T10:20:34.721Z
Learning: In hypercerts-org/ePDS: `atproto/oauth-client-node` does not allow adding custom parameters to Pushed Authorization Request (PAR) bodies. This is why `epds_handle_mode` cannot be sent via PAR and is exclusively delivered as a query parameter (`req.query.epds_handle_mode`). Do not suggest PAR as a delivery channel for any custom `epds_*` parameters when using this OAuth client library.
✅ Actions performed

Summary regeneration triggered.

@aspiers

aspiers commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

@bitbeckers @pheuberger Please note the above (even though Coderabbit failed to update the PR description).

aspiers added a commit that referenced this pull request Apr 9, 2026
The retroactive changesets added in #58 were all committed in the
same commit, so @changesets/changelog-github looked up that one
commit and used its PR (#58) and SHA on every generated entry in
the v0.2.0 release section. That's the generator behaving
correctly for its model (one changeset = one originating commit =
one originating PR) but it produces misleading "this change was
shipped in #58" refs when in reality each described feature
landed weeks earlier in a different PR.

Replace each bogus prefix with links to the real introducing
PR(s). Commit SHAs are dropped entirely because a feature that
spans multiple commits can't be meaningfully linked to a single
SHA, and the PR link already carries the useful context.

Future (non-retroactive) changesets won't hit this — they'll be
added in the same PR as the feature they describe, so the
generator's single-commit lookup resolves to the right PR
automatically. This fix is a one-off cleanup for the bootstrap
release.

PR → changeset mapping:
  #14 → Longer sign-in codes
  #13, #29, #33, #36 → Choose your own handle
  #3, #6 → Sign in faster from third-party apps
  #20, #23 → Fail-fast PDS_INTERNAL_URL validation
  #27 → Honour PORT env var
aspiers added a commit that referenced this pull request Apr 9, 2026
The retroactive changesets added in #58 were all committed in the
same commit, so @changesets/changelog-github looked up that one
commit and used its PR (#58) and SHA on every generated entry in
the v0.2.0 release section. That's the generator behaving
correctly for its model (one changeset = one originating commit =
one originating PR) but it produces misleading "this change was
shipped in #58" refs when in reality each described feature
landed weeks earlier in a different PR.

Replace each bogus prefix with links to the real introducing
PR(s). Commit SHAs are dropped entirely because a feature that
spans multiple commits can't be meaningfully linked to a single
SHA, and the PR link already carries the useful context.

Future (non-retroactive) changesets won't hit this — they'll be
added in the same PR as the feature they describe, so the
generator's single-commit lookup resolves to the right PR
automatically. This fix is a one-off cleanup for the bootstrap
release.

PR → changeset mapping:
  #14 → Longer sign-in codes
  #13, #29, #33, #36 → Choose your own handle
  #3, #6 → Sign in faster from third-party apps
  #20, #23 → Fail-fast PDS_INTERNAL_URL validation
  #27 → Honour PORT env var
aspiers added a commit that referenced this pull request Apr 11, 2026
…PER-301)

These features have been released since v0.2.0 but were missing from
docs/configuration.md.

Auth Service variables:
- OTP_LENGTH (4-12, default 8) and OTP_CHARSET (numeric/alphanumeric)
  added in v0.2.0 (#14).
- EPDS_DEFAULT_HANDLE_MODE (picker/random/picker-with-random) added in
  v0.2.0 (#13/#29/#33/#36).

Port rows now mention the v0.2.0 PORT fallback precedence (#27):
- auth service: AUTH_PORT -> PORT -> 3001
- pds-core:     PDS_PORT  -> PORT -> 3000

So that operators migrating pre-0.2.0 Railway setups learn they can drop
service-specific port overrides.

Refs HYPER-295.
aspiers added a commit that referenced this pull request Apr 11, 2026
Add an "Optional: control the handle picker" subsection under "Register
your app" covering:
- accepted values (picker / random / picker-with-random)
- the per-request precedence (query param -> client metadata -> env var
  -> built-in default)
- example client metadata JSON snippet and ?epds_handle_mode= query
  param override

This feature shipped in v0.2.0 (#13/#29/#33/#36) but was not visible to
client app developers reading docs/tutorial.md.

Refs HYPER-295.
@coderabbitai coderabbitai Bot mentioned this pull request Apr 27, 2026
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.

Make handle selection on signup optional

2 participants