@@ -82,6 +82,26 @@ const applyRetryDelay = async (config?: RetryConfig) => {
8282 * Note: The DPoP handle (oauth4webapi) is stateful and automatically learns nonces
8383 * from the DPoP-Nonce response header. No manual nonce injection is required.
8484 *
85+ * * ## Dual-Path Retry Logic
86+ *
87+ * The wrapper supports TWO different error paths, depending on how the caller
88+ * structures their token request:
89+ *
90+ * ### Path 1: HTTP Request Only (Recommended for Auth Code Flow)
91+ * **When to use:** Wrapping ONLY the HTTP request, not response processing*
92+ * **Error handling:**
93+ * - Nonce errors are detected via `response.status === 400` check (line 135)
94+ * - Non-nonce 400 errors pass through unchanged
95+ * - No exception is thrown; Response is returned for caller to process
96+ *
97+ * ### Path 2: HTTP Request + Response Processing (Used for Refresh/Connection Flows)
98+ * **When to use:** Wrapping both HTTP request AND response processing
99+ *
100+ * * **Error handling:**
101+ * - Nonce errors are detected via `isDPoPNonceError(error)` check (line 150)
102+ * - Non-nonce errors are re-thrown unchanged
103+ * - Caller receives either a successful response or an exception
104+ *
85105 * @template T - The return type of the function being executed
86106 * @param fn - The async function to execute with retry logic
87107 * @param config - Configuration object with retry behavior and DPoP enablement flag
@@ -128,6 +148,19 @@ export async function withDPoPNonceRetry<T>(
128148 return await fn ( ) ;
129149 }
130150
151+ /**
152+ * PATH 1: Response Object Inspection (Auth Code Flow)
153+ *
154+ * When fn() returns a Response object (not thrown), we check its status.
155+ * If 400 with use_dpop_nonce error, extract nonce from error body and retry.
156+ * This path is used when response processing happens OUTSIDE the wrapper.
157+ *
158+ * PATH 2: Exception Handling (Refresh/Connection Flows)
159+ * When fn() includes response processing that throws, we catch exceptions above.
160+ * Both paths support automatic nonce retry per RFC 9449 Section 8.
161+ *
162+ * @see withDPoPNonceRetry JSDoc for detailed explanation of dual-path retry logic
163+ */
131164 try {
132165 const response = await fn ( ) ;
133166
@@ -153,8 +186,7 @@ export async function withDPoPNonceRetry<T>(
153186 await applyRetryDelay ( config ) ;
154187 // Retry the request - the DPoP handle automatically learned the nonce
155188 return await fn ( ) ;
156- }
157- else {
189+ } else {
158190 throw error ;
159191 }
160192 }
0 commit comments