@@ -35,6 +35,7 @@ export function createRecoveryRouter(
3535
3636 router . get ( '/auth/recover' , ( req : Request , res : Response ) => {
3737 const requestUri = req . query . request_uri as string | undefined
38+ const clientId = req . query . client_id as string | undefined
3839
3940 if ( ! requestUri ) {
4041 res . status ( 400 ) . send ( renderError ( 'Missing request_uri parameter' ) )
@@ -44,6 +45,7 @@ export function createRecoveryRouter(
4445 res . type ( 'html' ) . send (
4546 renderRecoveryForm ( {
4647 requestUri,
48+ clientId,
4749 csrfToken : res . locals . csrfToken ,
4850 } ) ,
4951 )
@@ -52,11 +54,13 @@ export function createRecoveryRouter(
5254 router . post ( '/auth/recover' , async ( req : Request , res : Response ) => {
5355 const email = ( ( req . body . email as string ) || '' ) . trim ( ) . toLowerCase ( )
5456 const requestUri = req . body . request_uri as string
57+ const clientId = ( req . body . client_id as string | undefined ) || undefined
5558
5659 if ( ! email || ! requestUri ) {
5760 res . status ( 400 ) . send (
5861 renderRecoveryForm ( {
5962 requestUri : requestUri || '' ,
63+ clientId,
6064 csrfToken : res . locals . csrfToken ,
6165 error : 'Email and request URI are required.' ,
6266 } ) ,
@@ -68,6 +72,7 @@ export function createRecoveryRouter(
6872 res . status ( 400 ) . send (
6973 renderRecoveryForm ( {
7074 requestUri,
75+ clientId,
7176 csrfToken : res . locals . csrfToken ,
7277 error : 'Please enter a valid email address.' ,
7378 } ) ,
@@ -111,6 +116,7 @@ export function createRecoveryRouter(
111116 email,
112117 csrfToken : res . locals . csrfToken ,
113118 requestUri,
119+ clientId,
114120 otpLength,
115121 otpCharset,
116122 } ) ,
@@ -122,6 +128,7 @@ export function createRecoveryRouter(
122128 email,
123129 csrfToken : res . locals . csrfToken ,
124130 requestUri,
131+ clientId,
125132 error : 'Failed to send code. Please try again.' ,
126133 otpLength,
127134 otpCharset,
@@ -135,6 +142,7 @@ export function createRecoveryRouter(
135142 email,
136143 csrfToken : res . locals . csrfToken ,
137144 requestUri,
145+ clientId,
138146 otpLength,
139147 otpCharset,
140148 } ) ,
@@ -201,12 +209,16 @@ export function createRecoveryRouter(
201209 return router
202210}
203211
204- function renderRecoveryForm ( opts : {
212+ export function renderRecoveryForm ( opts : {
205213 requestUri : string
206214 csrfToken : string
215+ clientId ?: string
207216 error ?: string
208217} ) : string {
209218 const encodedUri = encodeURIComponent ( opts . requestUri )
219+ const clientIdParam = opts . clientId
220+ ? `&client_id=${ encodeURIComponent ( opts . clientId ) } `
221+ : ''
210222 const errorHtml = opts . error
211223 ? `<div class="admonition error" role="alert">
212224 <span class="admonition-icon" aria-hidden="true">
@@ -239,6 +251,7 @@ function renderRecoveryForm(opts: {
239251 <form method="POST" action="/auth/recover">
240252 <input type="hidden" name="csrf" value="${ escapeHtml ( opts . csrfToken ) } ">
241253 <input type="hidden" name="request_uri" value="${ escapeHtml ( opts . requestUri ) } ">
254+ ${ opts . clientId ? `<input type="hidden" name="client_id" value="${ escapeHtml ( opts . clientId ) } ">` : '' }
242255 <div class="field">
243256 <label class="field-label" for="email">Backup email address</label>
244257 <div class="input-container">
@@ -254,7 +267,7 @@ function renderRecoveryForm(opts: {
254267 </div>
255268 </div>
256269 <div class="form-actions">
257- <a href="/oauth/authorize?request_uri=${ encodedUri } " class="link-btn">Back to sign in</a>
270+ <a href="/oauth/authorize?request_uri=${ encodedUri } ${ clientIdParam } " class="link-btn">Back to sign in</a>
258271 <button type="submit" class="btn-primary">Send Recovery Code</button>
259272 </div>
260273 </form>
@@ -264,16 +277,20 @@ function renderRecoveryForm(opts: {
264277</html>`
265278}
266279
267- function renderOtpForm ( opts : {
280+ export function renderOtpForm ( opts : {
268281 email : string
269282 csrfToken : string
270283 requestUri : string
271284 otpLength : number
272285 otpCharset : 'numeric' | 'alphanumeric'
286+ clientId ?: string
273287 error ?: string
274288} ) : string {
275289 const maskedEmail = maskEmail ( opts . email )
276290 const encodedUri = encodeURIComponent ( opts . requestUri )
291+ const clientIdParam = opts . clientId
292+ ? `&client_id=${ encodeURIComponent ( opts . clientId ) } `
293+ : ''
277294 const inputProps = buildOtpInputProps ( opts . otpLength , opts . otpCharset )
278295 const errorHtml = opts . error
279296 ? `<div class="admonition error" role="alert">
@@ -330,13 +347,13 @@ function renderOtpForm(opts: {
330347 </div>
331348 <div class="form-actions">
332349 <div class="otp-links">
333- <a href="/oauth/authorize?request_uri=${ encodedUri } " class="link-btn">Back to sign in</a>
350+ <a href="/oauth/authorize?request_uri=${ encodedUri } ${ clientIdParam } " class="link-btn">Back to sign in</a>
334351 <span class="otp-links-dot">·</span>
335- <form method="POST" action="/auth/recover" class="inline-form">
352+ <form method="POST" action="/auth/recover" class="inline-form">
336353 <input type="hidden" name="csrf" value="${ escapeHtml ( opts . csrfToken ) } ">
337354 <input type="hidden" name="request_uri" value="${ escapeHtml ( opts . requestUri ) } ">
338355 <input type="hidden" name="email" value="${ escapeHtml ( opts . email ) } ">
339- <button type="submit" class="link-btn">Resend Code</button>
356+ <button type="submit" class="link-btn" formnovalidate >Resend Code</button>
340357 </form>
341358 </div>
342359 <button type="submit" class="btn-primary">Verify</button>
0 commit comments