{"record":{"id":"1629192f2d6d24cf","repo":"medusajs/medusa","slug":"invalid-token-162919","errorCode":null,"errorMessage":"Invalid token","messagePattern":"Invalid token","errorType":"exception","errorClass":"MedusaError","httpStatus":401,"severity":"error","filePath":"packages/modules/auth/src/services/auth-module.ts","lineNumber":925,"sourceCode":"    data: AuthTypes.ConsumePasswordResetTokenDTO,\n    @MedusaContext() sharedContext: Context = {}\n  ): Promise<AuthTypes.ConsumePasswordResetTokenResponse> {\n    return await this.consumePasswordResetToken_(data, sharedContext)\n  }\n\n  @InjectTransactionManager()\n  protected async consumePasswordResetToken_(\n    data: AuthTypes.ConsumePasswordResetTokenDTO,\n    @MedusaContext() sharedContext: Context = {}\n  ): Promise<AuthTypes.ConsumePasswordResetTokenResponse> {\n    const [resetToken] = await this.authPasswordResetTokenService_.list(\n      { token_hash: this.hashVerificationToken_(data.jti) },\n      {},\n      sharedContext\n    )\n\n    if (!resetToken) {\n      throw new MedusaError(MedusaError.Types.UNAUTHORIZED, \"Invalid token\")\n    }\n\n    if (new Date(resetToken.expires_at).getTime() <= Date.now()) {\n      await this.authPasswordResetTokenService_.delete(\n        resetToken.id,\n        sharedContext\n      )\n      throw new MedusaError(MedusaError.Types.UNAUTHORIZED, \"Invalid token\")\n    }\n\n    const providerIdentity = await this.providerIdentityService_.retrieve(\n      resetToken.provider_identity_id,\n      {},\n      sharedContext\n    )\n\n    if (\n      providerIdentity.provider !== data.provider ||","sourceCodeStart":907,"sourceCodeEnd":943,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/auth/src/services/auth-module.ts#L907-L943","documentation":"Thrown by consumePasswordResetToken when no stored reset token matches the hash of the submitted jti. UNAUTHORIZED: the token is unknown — never issued, already consumed, or corrupted.","triggerScenarios":"Consuming a token twice (tokens are deleted after use); using a token from a different environment/database; malformed or truncated jti; token rows purged.","commonSituations":"User clicks an old reset link after already resetting; double-click on the confirm link; env drift between staging and production tokens.","solutions":["Treat as consumed/invalid: restart the reset flow with a new token request","Ensure the token value is passed intact (no URL-encoding truncation)","Verify environment/database consistency between issuance and consumption"],"exampleFix":"// before\nawait authModule.consumePasswordResetToken({ jti: token, entity_id, provider })\n// after\nconst result = await authModule.consumePasswordResetToken({ jti: token, entity_id, provider }).catch((e) => {\n  if (e.type === 'unauthorized') throw new Error('Reset link invalid or already used — request a new one')\n  throw e\n})","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"try { await authModule.consumePasswordResetToken(input) } catch (e) { if (e.type === 'unauthorized') redirect('/reset?expired=1'); throw e }","preventionTips":["Never consume a token twice; consume once at confirmation","Pass the jti intact from the link"],"tags":["auth","password-reset","token","unauthorized"],"backgroundTag":"invalid-reset-token","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}