Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/clear-otp-boxes-on-resend.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Asking for a new sign-in code now clears the boxes and tells you the old code ha

**Affects:** End users

**End users:** the boxes reset on **Resend code**, so a half-typed old code no longer has to be deleted by hand before you can type the new one. The confirmation message that replaces "Code resent!" also warns that only the newest code will be accepted, and points at the spam folder — the two things most likely to be going wrong for anyone who got as far as resending.
**End users:** the boxes reset on **Send a new code**, so a half-typed old code no longer has to be deleted by hand before you can type the new one. The confirmation also warns that only the newest code will be accepted, and points at the spam folder — the two things most likely to be going wrong for anyone who got that far.
9 changes: 9 additions & 0 deletions .changeset/send-a-new-code-label.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'ePDS': patch
---

The sign-in button that emails you another code now says "Send a new code" instead of "Resend code".

**Affects:** End users

**End users:** each request emails a genuinely new code and stops the previous one working, so "Resend" was misleading — it suggested the code already in your inbox was still the one to type. The confirmation after clicking now starts "Sent!" rather than "Resent!", and still tells you that earlier codes no longer work. The same wording appears on the recovery and account sign-in pages, and on the link offered beside a rejected or expired code.
Comment thread
aspiers marked this conversation as resolved.
2 changes: 1 addition & 1 deletion .changeset/sign-in-errors-at-point-of-failure.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ Sign-in error messages now appear next to the field that caused them, instead of

**End users:** a rejected sign-in code used to report the problem above the page heading, several elements away from the boxes you had just typed into — easy to miss, and it left the **Verify** button looking like the thing to press again. The message now sits directly between the code boxes and **Verify**, and a failed email submission likewise reads under the email field rather than above it.

A rejected code now also carries a **Resend code** link beside the message. The standalone button below the form was easy to overlook, and "that code didn't work" often means there is no usable code left at all rather than that you mistyped it — after too many wrong attempts, after signing in from another tab, or once an old code has aged out. Retyping cannot recover any of those. The boxes still clear and refocus, so retyping remains one keystroke away when that is what you need.
A rejected code now also carries a **Send a new code** link beside the message. The standalone button below the form was easy to overlook, and "that code didn't work" often means there is no usable code left at all rather than that you mistyped it — after too many wrong attempts, after signing in from another tab, or once an old code has aged out. Retyping cannot recover any of those. The boxes still clear and refocus, so retyping remains one keystroke away when that is what you need.
2 changes: 1 addition & 1 deletion e2e/step-definitions/auth.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ When('the OTP form re-checks PAR liveness', async function (this: EpdsWorld) {
})

Then(
'the Resend code button is no longer offered',
'the Send a new code button is no longer offered',
async function (this: EpdsWorld) {
const page = getPage(this)
await expect(page.locator('#btn-resend')).toBeHidden({ timeout: 5_000 })
Expand Down
2 changes: 1 addition & 1 deletion features/passwordless-authentication.feature
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ Feature: Passwordless authentication via email OTP
And the login page shows an OTP verification form
When the PAR request_uri has expired before the bridge fires
And the OTP form re-checks PAR liveness
Then the Resend code button is no longer offered
Then the Send a new code button is no longer offered
And a Start over button is offered instead

# The demo OAuth client stores its OAuth state (state value, code
Expand Down
2 changes: 1 addition & 1 deletion packages/auth-service/src/__tests__/login-page.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ describe('renderLoginPage inline Resend action on expired OTP', () => {
// after expiry cleanup. Retyping cannot recover any of those, so
// the action must not be withheld from the plain-invalid branch.
expect(html).toMatch(
/else if \(!parLikelyDead\(\)\)[\s\S]*?showErrorWithAction\(\s*result\.error,\s*'Resend code'/,
/else if \(!parLikelyDead\(\)\)[\s\S]*?showErrorWithAction\(\s*result\.error,\s*'Send a new code'/,
)
})

Expand Down
2 changes: 1 addition & 1 deletion packages/auth-service/src/routes/account-login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ function renderOtpForm(opts: {
<form method="POST" action="/account/send-otp" style="margin-top: 12px;">
<input type="hidden" name="csrf" value="${escapeHtml(opts.csrfToken)}">
<input type="hidden" name="email" value="${escapeHtml(opts.email)}">
<button type="submit" class="btn-secondary">Resend code</button>
<button type="submit" class="btn-secondary">Send a new code</button>
</form>
</div>
${POWERED_BY_HTML}
Expand Down
10 changes: 5 additions & 5 deletions packages/auth-service/src/routes/login-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ export function renderLoginPage(opts: {
<button type="submit" class="btn-primary">Verify</button>
</form>
<div class="otp-actions">
<button type="button" class="btn-secondary" id="btn-resend">Resend code</button>
<button type="button" class="btn-secondary" id="btn-resend">Send a new code</button>
<button type="button" class="btn-secondary" id="btn-back">Use different email</button>
</div>
<a href="/auth/recover?request_uri=${encodeURIComponent(opts.pdsPublicUrl + '/placeholder')}"
Expand Down Expand Up @@ -1358,7 +1358,7 @@ export function renderLoginPage(opts: {
// would re-offer an action the page has deliberately
// withdrawn. The aborted-flow notice carries its own
// restart action, so nothing is lost by staying quiet.
showErrorWithAction(result.error, 'Resend code', function() {
showErrorWithAction(result.error, 'Send a new code', function() {
document.getElementById('btn-resend').click();
});
} else {
Expand All @@ -1384,7 +1384,7 @@ export function renderLoginPage(opts: {
}
});

// Resend code
// Send a new code (the element id predates the relabel)
document.getElementById('btn-resend').addEventListener('click', async function() {
clearError();
this.disabled = true;
Expand All @@ -1396,7 +1396,7 @@ export function renderLoginPage(opts: {
if (await abortIfFlowDead()) return;
var result = await sendOtp(currentEmail);
this.disabled = false;
this.textContent = 'Resend code';
this.textContent = 'Send a new code';
Comment thread
aspiers marked this conversation as resolved.
if (result.error) {
showError(result.error);
} else {
Expand All @@ -1409,7 +1409,7 @@ export function renderLoginPage(opts: {
// sending a new OTP invalidates every earlier one, and a user
// who needed to resend is the user whose mail may be in spam.
showSuccess(
'Resent! Make sure to use the new code; earlier ones no longer work. ' +
'Sent! Make sure to use the new code; earlier ones no longer work. ' +
'It may be in your spam folder.',
);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/auth-service/src/routes/recovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ export function renderRecoveryOtpForm(opts: {
<input type="hidden" name="request_uri" value="${escapeHtml(opts.requestUri)}">
<input type="hidden" name="email" value="${escapeHtml(opts.email)}">
${noHeartbeatField}
<button type="submit" class="btn-secondary">Resend code</button>
<button type="submit" class="btn-secondary">Send a new code</button>
</form>
<a href="${backHref}" class="btn-secondary">Back to sign in</a>
</div>
Expand Down
Loading