[{"data":1,"prerenderedAt":3286},["ShallowReactive",2],{"navLinks":3,"sidebar_docs_navigation_\u002Fdocs\u002Fiam":64,"navigation":257,"navLinks_footer":837,"\u002Fdocs\u002Fiam\u002Fessentials\u002Fhmac_page":850,"\u002Fdocs\u002Fiam\u002Fessentials\u002Fhmac_surround":2267,"\u002Fdocs\u002Fiam\u002Fessentials\u002Fhmac":2270},{"id":4,"extension":5,"links":6,"meta":61,"stem":62,"__hash__":63},"navigationMenu\u002Fnavigation.json","json",[7,52,57],{"nested":8,"label":9,"icon":10,"to":11,"children":12},true,"Docs","i-lucide-book-open","\u002Fdocs\u002Fgetting-started",[13,19,26,32,39,45],{"label":14,"icon":15,"to":11,"description":16,"github":17,"badge":18},"Getting Started","i-lucide-rocket","An introduction to help you understand the core components.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Fdocshub","Start Here",{"label":20,"icon":21,"to":22,"description":23,"github":24,"badge":25},"Auth H3 Client","i-lucide-key-round","\u002Fdocs\u002Fauth-h3client","Seamlessly enforce OAuth 2.0 authentication and session management integrated directly as the client of the IAM module.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Fauth-h3client","Core",{"label":27,"icon":28,"to":29,"description":30,"github":31,"badge":25},"IAM","i-lucide-shield-check","\u002Fdocs\u002Fiam","Identity and Access Management featuring granular roles, permissions, and security policies.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Fauth",{"label":33,"icon":34,"to":35,"description":36,"github":37,"badge":38},"Bot Detection","i-lucide-cpu","\u002Fdocs\u002Fbot-detection","Advanced behavioral analysis and request fingerprinting to stop malicious automated traffic.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Fbot-detector","Security",{"label":40,"icon":41,"to":42,"description":43,"github":44,"badge":38},"Shield Base","i-lucide-database-zap","\u002Fdocs\u002Fshield-base","CLI and programmatic toolkit for compiling offline-ready IP intelligence databases from BGP, GeoIP, Tor, FireHOL, and other public threat feeds.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Fshield-base-cli",{"label":46,"icon":47,"to":48,"description":49,"github":50,"badge":51},"Utils","i-lucide-wrench","\u002Fdocs\u002Futils","A standard library of highly optimized helpers for formatting, validation, and core logic.","https:\u002F\u002Fgithub.com\u002FSergo706\u002Futils","Library",{"nested":53,"label":54,"icon":55,"to":56},false,"Blog","i-lucide-pen-line","\u002Fblog",{"nested":53,"label":58,"icon":59,"to":60},"Website","lucide:app-window-mac","https:\u002F\u002Friavzon.com",{},"navigation","gkaQ0xRGxSLrLyM3kttLe0oBwkrR1EBjlepF8LSbwF8",[65],{"title":9,"path":66,"stem":67,"children":68,"page":53},"\u002Fdocs","docs",[69],{"title":27,"path":29,"stem":70,"children":71},"docs\u002Fiam\u002Findex",[72,73,76,216,219,236,240],{"title":27,"path":29,"stem":70},{"title":14,"path":74,"stem":75},"\u002Fdocs\u002Fiam\u002Fgetting-started","docs\u002Fiam\u002F00.getting-started",{"title":77,"path":78,"stem":79,"children":80},"Essentials","\u002Fdocs\u002Fiam\u002Fessentials","docs\u002Fiam\u002F01.essentials\u002Findex",[81,82,86,90,94,98,102,106,110,114,118,122,126,130,134,138,142,146,150,154,158,162,166],{"title":77,"path":78,"stem":79},{"title":83,"path":84,"stem":85},"Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Ftokens","docs\u002Fiam\u002F01.essentials\u002F00.tokens",{"title":87,"path":88,"stem":89},"Access Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Faccess-tokens","docs\u002Fiam\u002F01.essentials\u002F01.access-tokens",{"title":91,"path":92,"stem":93},"Refresh Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Frefresh-tokens","docs\u002Fiam\u002F01.essentials\u002F02.refresh-tokens",{"title":95,"path":96,"stem":97},"Anomaly Detection","\u002Fdocs\u002Fiam\u002Fessentials\u002Fanomalies","docs\u002Fiam\u002F01.essentials\u002F03.anomalies",{"title":99,"path":100,"stem":101},"Signup","\u002Fdocs\u002Fiam\u002Fessentials\u002Fsignup","docs\u002Fiam\u002F01.essentials\u002F04.signup",{"title":103,"path":104,"stem":105},"Login","\u002Fdocs\u002Fiam\u002Fessentials\u002Flogin","docs\u002Fiam\u002F01.essentials\u002F05.login",{"title":107,"path":108,"stem":109},"Logout","\u002Fdocs\u002Fiam\u002Fessentials\u002Flogout","docs\u002Fiam\u002F01.essentials\u002F06.logout",{"title":111,"path":112,"stem":113},"OAuth","\u002Fdocs\u002Fiam\u002Fessentials\u002Foauth","docs\u002Fiam\u002F01.essentials\u002F07.oauth",{"title":115,"path":116,"stem":117},"Magic Links","\u002Fdocs\u002Fiam\u002Fessentials\u002Fmagic-links","docs\u002Fiam\u002F01.essentials\u002F08.magic-links",{"title":119,"path":120,"stem":121},"Emails","\u002Fdocs\u002Fiam\u002Fessentials\u002Femails","docs\u002Fiam\u002F01.essentials\u002F09.emails",{"title":123,"path":124,"stem":125},"MFA","\u002Fdocs\u002Fiam\u002Fessentials\u002Fmfa","docs\u002Fiam\u002F01.essentials\u002F10.mfa",{"title":127,"path":128,"stem":129},"Fingerprinting","\u002Fdocs\u002Fiam\u002Fessentials\u002Ffingerprinting","docs\u002Fiam\u002F01.essentials\u002F11.fingerprinting",{"title":131,"path":132,"stem":133},"Backend for Frontend","\u002Fdocs\u002Fiam\u002Fessentials\u002Fbff","docs\u002Fiam\u002F01.essentials\u002F12.bff",{"title":135,"path":136,"stem":137},"HMAC Authentication","\u002Fdocs\u002Fiam\u002Fessentials\u002Fhmac","docs\u002Fiam\u002F01.essentials\u002F13.hmac",{"title":139,"path":140,"stem":141},"XSS Protection","\u002Fdocs\u002Fiam\u002Fessentials\u002Fxss","docs\u002Fiam\u002F01.essentials\u002F14.xss",{"title":143,"path":144,"stem":145},"Logging","\u002Fdocs\u002Fiam\u002Fessentials\u002Flogging","docs\u002Fiam\u002F01.essentials\u002F15.logging",{"title":147,"path":148,"stem":149},"Rate Limiting","\u002Fdocs\u002Fiam\u002Fessentials\u002Frate-limiting","docs\u002Fiam\u002F01.essentials\u002F16.rate-limiting",{"title":151,"path":152,"stem":153},"Database","\u002Fdocs\u002Fiam\u002Fessentials\u002Fdatabase","docs\u002Fiam\u002F01.essentials\u002F17.database",{"title":155,"path":156,"stem":157},"Cookies","\u002Fdocs\u002Fiam\u002Fessentials\u002Fcookies","docs\u002Fiam\u002F01.essentials\u002F18.cookies",{"title":159,"path":160,"stem":161},"Service Startup","\u002Fdocs\u002Fiam\u002Fessentials\u002Fservice","docs\u002Fiam\u002F01.essentials\u002F19.service",{"title":163,"path":164,"stem":165},"Password Reset","\u002Fdocs\u002Fiam\u002Fessentials\u002Fpassword-reset","docs\u002Fiam\u002F01.essentials\u002F20.password-reset",{"title":167,"path":168,"stem":169,"children":170},"API Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi","docs\u002Fiam\u002F01.essentials\u002F21.api\u002Findex",[171,172,176,180,210,213],{"title":167,"path":168,"stem":169},{"title":173,"path":174,"stem":175},"Creating Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fcreation","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F00.creation",{"title":177,"path":178,"stem":179},"Verifying Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fverification","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F01.verification",{"title":181,"path":182,"stem":183,"children":184},"Manage Tokens","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002Findex",[185,186,190,194,198,202,206],{"title":181,"path":182,"stem":183},{"title":187,"path":188,"stem":189},"Privileges","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Fprivilege","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F00.privilege",{"title":191,"path":192,"stem":193},"Revocation","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Frevocation","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F01.revocation",{"title":195,"path":196,"stem":197},"Rotation","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Frotation","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F02.rotation",{"title":199,"path":200,"stem":201},"IP Restriction","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Fip-updates","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F03.ip-updates",{"title":203,"path":204,"stem":205},"Metadata","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Fmetadata","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F04.metadata",{"title":207,"path":208,"stem":209},"Token Listing","\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fmanagement\u002Flist","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F02.management\u002F05.list",{"title":147,"path":211,"stem":212},"\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Frate-limiting","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F03.rate-limiting",{"title":38,"path":214,"stem":215},"\u002Fdocs\u002Fiam\u002Fessentials\u002Fapi\u002Fsecurity","docs\u002Fiam\u002F01.essentials\u002F21.api\u002F04.security",{"title":38,"path":217,"stem":218},"\u002Fdocs\u002Fiam\u002Fsecurity","docs\u002Fiam\u002F02.security",{"title":220,"path":221,"stem":222,"children":223,"page":53},"Guides","\u002Fdocs\u002Fiam\u002Fguides","docs\u002Fiam\u002F03.guides",[224,228,232],{"title":225,"path":226,"stem":227},"Deployment","\u002Fdocs\u002Fiam\u002Fguides\u002Fdeployment","docs\u002Fiam\u002F03.guides\u002Fdeployment",{"title":229,"path":230,"stem":231},"Operation Scripts","\u002Fdocs\u002Fiam\u002Fguides\u002Foperation-scripts","docs\u002Fiam\u002F03.guides\u002Foperation-scripts",{"title":233,"path":234,"stem":235},"Role-Based Access Control","\u002Fdocs\u002Fiam\u002Fguides\u002Frbac","docs\u002Fiam\u002F03.guides\u002Frbac",{"title":237,"path":238,"stem":239},"Configuration","\u002Fdocs\u002Fiam\u002Fconfiguration","docs\u002Fiam\u002F04.configuration",{"title":241,"path":242,"stem":243,"children":244,"page":53},"Api","\u002Fdocs\u002Fiam\u002Fapi","docs\u002Fiam\u002F05.API",[245,249,253],{"title":246,"path":247,"stem":248},"API Reference","\u002Fdocs\u002Fiam\u002Fapi\u002Fapi","docs\u002Fiam\u002F05.API\u002F00.api",{"title":250,"path":251,"stem":252},"Middleware Reference","\u002Fdocs\u002Fiam\u002Fapi\u002Fmiddlewares","docs\u002Fiam\u002F05.API\u002F02.middlewares",{"title":254,"path":255,"stem":256},"Routes Reference","\u002Fdocs\u002Fiam\u002Fapi\u002Froutes","docs\u002Fiam\u002F05.API\u002F03.routes",[258],{"title":9,"path":66,"stem":67,"children":259,"page":53},[260,398,516,521,577,644],{"title":20,"path":22,"stem":261,"children":262},"docs\u002Fauth-h3client\u002Findex",[263,264,273,307,331,353,356,376,379],{"title":20,"path":22,"stem":261},{"title":14,"path":265,"stem":266,"children":267},"\u002Fdocs\u002Fauth-h3client\u002Fgetting-started","docs\u002Fauth-h3client\u002F00.getting-started\u002Findex",[268,269],{"title":14,"path":265,"stem":266},{"title":270,"path":271,"stem":272},"Nuxt Module","\u002Fdocs\u002Fauth-h3client\u002Fgetting-started\u002Fnuxt","docs\u002Fauth-h3client\u002F00.getting-started\u002F00.nuxt",{"title":77,"path":274,"stem":275,"children":276},"\u002Fdocs\u002Fauth-h3client\u002Fessentials","docs\u002Fauth-h3client\u002F01.essentials\u002Findex",[277,278,282,286,290,294,298,301,304],{"title":77,"path":274,"stem":275},{"title":279,"path":280,"stem":281},"Session Management","\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Fsession","docs\u002Fauth-h3client\u002F01.essentials\u002F00.session",{"title":283,"path":284,"stem":285},"Route Protection","\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Froute-protection","docs\u002Fauth-h3client\u002F01.essentials\u002F01.route-protection",{"title":287,"path":288,"stem":289},"CSRF Protection","\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Fcsrf","docs\u002Fauth-h3client\u002F01.essentials\u002F02.csrf",{"title":291,"path":292,"stem":293},"Auth Flows","\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Fauth-flows","docs\u002Fauth-h3client\u002F01.essentials\u002F03.auth-flows",{"title":295,"path":296,"stem":297},"OAuth and OIDC","\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Foauth","docs\u002Fauth-h3client\u002F01.essentials\u002F04.oauth",{"title":33,"path":299,"stem":300},"\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Fbot-detection","docs\u002Fauth-h3client\u002F01.essentials\u002F05.bot-detection",{"title":155,"path":302,"stem":303},"\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Fcookies","docs\u002Fauth-h3client\u002F01.essentials\u002F06.cookies",{"title":143,"path":305,"stem":306},"\u002Fdocs\u002Fauth-h3client\u002Fessentials\u002Flogging","docs\u002Fauth-h3client\u002F01.essentials\u002F07.logging",{"title":123,"path":308,"stem":309,"children":310},"\u002Fdocs\u002Fauth-h3client\u002Fmfa","docs\u002Fauth-h3client\u002F02.mfa\u002Findex",[311,312,316,319,323,327],{"title":123,"path":308,"stem":309},{"title":313,"path":314,"stem":315},"Built-in MFA","\u002Fdocs\u002Fauth-h3client\u002Fmfa\u002Fbuilt-in-flow","docs\u002Fauth-h3client\u002F02.mfa\u002F01.built-in-flow",{"title":163,"path":317,"stem":318},"\u002Fdocs\u002Fauth-h3client\u002Fmfa\u002Fpassword-reset","docs\u002Fauth-h3client\u002F02.mfa\u002F02.password-reset",{"title":320,"path":321,"stem":322},"Email Change","\u002Fdocs\u002Fauth-h3client\u002Fmfa\u002Femail-change","docs\u002Fauth-h3client\u002F02.mfa\u002F03.email-change",{"title":324,"path":325,"stem":326},"Custom MFA Flow","\u002Fdocs\u002Fauth-h3client\u002Fmfa\u002Fcustom-flow","docs\u002Fauth-h3client\u002F02.mfa\u002F04.custom-flow",{"title":328,"path":329,"stem":330},"Client-Side MFA","\u002Fdocs\u002Fauth-h3client\u002Fmfa\u002Fclient-side","docs\u002Fauth-h3client\u002F02.mfa\u002F05.client-side",{"title":332,"path":333,"stem":334,"children":335},"Client-side","\u002Fdocs\u002Fauth-h3client\u002Fclient","docs\u002Fauth-h3client\u002F03.client\u002Findex",[336,337,341,345,349],{"title":332,"path":333,"stem":334},{"title":338,"path":339,"stem":340},"useAuthData","\u002Fdocs\u002Fauth-h3client\u002Fclient\u002Fuse-auth-data","docs\u002Fauth-h3client\u002F03.client\u002F00.use-auth-data",{"title":342,"path":343,"stem":344},"useMagicLink","\u002Fdocs\u002Fauth-h3client\u002Fclient\u002Fuse-magic-link","docs\u002Fauth-h3client\u002F03.client\u002F01.use-magic-link",{"title":346,"path":347,"stem":348},"executeRequest","\u002Fdocs\u002Fauth-h3client\u002Fclient\u002Fexecute-request","docs\u002Fauth-h3client\u002F03.client\u002F02.execute-request",{"title":350,"path":351,"stem":352},"getCsrfToken","\u002Fdocs\u002Fauth-h3client\u002Fclient\u002Fget-csrf-token","docs\u002Fauth-h3client\u002F03.client\u002F03.get-csrf-token",{"title":38,"path":354,"stem":355},"\u002Fdocs\u002Fauth-h3client\u002Fsecurity","docs\u002Fauth-h3client\u002F04.security",{"title":220,"path":357,"stem":358,"children":359,"page":53},"\u002Fdocs\u002Fauth-h3client\u002Fguides","docs\u002Fauth-h3client\u002F05.guides",[360,364,368,372],{"title":361,"path":362,"stem":363},"H3 and Nitro Setup","\u002Fdocs\u002Fauth-h3client\u002Fguides\u002Fh3-nitro","docs\u002Fauth-h3client\u002F05.guides\u002F00.h3-nitro",{"title":365,"path":366,"stem":367},"HMAC Inter-service Auth","\u002Fdocs\u002Fauth-h3client\u002Fguides\u002Fhmac","docs\u002Fauth-h3client\u002F05.guides\u002Fhmac",{"title":369,"path":370,"stem":371},"Image Upload","\u002Fdocs\u002Fauth-h3client\u002Fguides\u002Fimage-upload","docs\u002Fauth-h3client\u002F05.guides\u002Fimage-upload",{"title":373,"path":374,"stem":375},"mTLS Configuration","\u002Fdocs\u002Fauth-h3client\u002Fguides\u002Fmtls","docs\u002Fauth-h3client\u002F05.guides\u002Fmtls",{"title":237,"path":377,"stem":378},"\u002Fdocs\u002Fauth-h3client\u002Fconfiguration","docs\u002Fauth-h3client\u002F06.configuration",{"title":246,"path":380,"stem":381,"children":382},"\u002Fdocs\u002Fauth-h3client\u002Fapi","docs\u002Fauth-h3client\u002F07.api\u002Findex",[383,384,387,390,394],{"title":246,"path":380,"stem":381},{"title":254,"path":385,"stem":386},"\u002Fdocs\u002Fauth-h3client\u002Fapi\u002Fcontrollers","docs\u002Fauth-h3client\u002F07.api\u002F00.controllers",{"title":250,"path":388,"stem":389},"\u002Fdocs\u002Fauth-h3client\u002Fapi\u002Fmiddleware","docs\u002Fauth-h3client\u002F07.api\u002F01.middleware",{"title":391,"path":392,"stem":393},"Client-side Reference","\u002Fdocs\u002Fauth-h3client\u002Fapi\u002Fcomposables","docs\u002Fauth-h3client\u002F07.api\u002F02.composables",{"title":395,"path":396,"stem":397},"Utilities","\u002Fdocs\u002Fauth-h3client\u002Fapi\u002Futilities","docs\u002Fauth-h3client\u002F07.api\u002F03.utilities",{"title":399,"path":35,"stem":400,"children":401},"Bot Detector","docs\u002Fbot-detection\u002Findex",[402,403,406,410,414,433,507,510,513],{"title":399,"path":35,"stem":400},{"title":14,"path":404,"stem":405},"\u002Fdocs\u002Fbot-detection\u002Fgetting-started","docs\u002Fbot-detection\u002F00.getting-started",{"title":407,"path":408,"stem":409},"CLI","\u002Fdocs\u002Fbot-detection\u002Fcli","docs\u002Fbot-detection\u002F01.cli",{"title":411,"path":412,"stem":413},"Data Sources","\u002Fdocs\u002Fbot-detection\u002Fdata-sources","docs\u002Fbot-detection\u002F02.data-sources",{"title":220,"path":415,"stem":416,"children":417,"page":53},"\u002Fdocs\u002Fbot-detection\u002Fguides","docs\u002Fbot-detection\u002F03.guides",[418,422,426,429],{"title":419,"path":420,"stem":421},"Custom Checkers","\u002Fdocs\u002Fbot-detection\u002Fguides\u002Fcustom","docs\u002Fbot-detection\u002F03.guides\u002FCUSTOM",{"title":423,"path":424,"stem":425},"Scheduling Database Generation","\u002Fdocs\u002Fbot-detection\u002Fguides\u002Fgenerate","docs\u002Fbot-detection\u002F03.guides\u002FGENERATE",{"title":143,"path":427,"stem":428},"\u002Fdocs\u002Fbot-detection\u002Fguides\u002Flogging","docs\u002Fbot-detection\u002F03.guides\u002FLOGGING",{"title":430,"path":431,"stem":432},"Score Modes and Reputation Healing","\u002Fdocs\u002Fbot-detection\u002Fguides\u002Fscore","docs\u002Fbot-detection\u002F03.guides\u002FSCORE",{"title":434,"path":435,"stem":436,"children":437},"Checkers","\u002Fdocs\u002Fbot-detection\u002Fcheckers","docs\u002Fbot-detection\u002F04.checkers\u002Findex",[438,439,443,447,451,455,459,463,467,471,475,479,483,487,491,495,499,503],{"title":434,"path":435,"stem":436},{"title":440,"path":441,"stem":442},"IP Validation","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fip-validation","docs\u002Fbot-detection\u002F04.checkers\u002F01.ip-validation",{"title":444,"path":445,"stem":446},"Good \u002F Bad Bot Verification","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fgood-bots","docs\u002Fbot-detection\u002F04.checkers\u002F02.good-bots",{"title":448,"path":449,"stem":450},"Browser & Device Fingerprint","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fbrowser-device","docs\u002Fbot-detection\u002F04.checkers\u002F03.browser-device",{"title":452,"path":453,"stem":454},"Locale Map","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Flocale-map","docs\u002Fbot-detection\u002F04.checkers\u002F04.locale-map",{"title":456,"path":457,"stem":458},"Known Threats","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fknown-threats","docs\u002Fbot-detection\u002F04.checkers\u002F05.known-threats",{"title":460,"path":461,"stem":462},"ASN Classification","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fasn-classification","docs\u002Fbot-detection\u002F04.checkers\u002F06.asn-classification",{"title":464,"path":465,"stem":466},"Tor Analysis","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Ftor-analysis","docs\u002Fbot-detection\u002F04.checkers\u002F07.tor-analysis",{"title":468,"path":469,"stem":470},"Timezone Consistency","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Ftimezone-consistency","docs\u002Fbot-detection\u002F04.checkers\u002F08.timezone-consistency",{"title":472,"path":473,"stem":474},"Honeypot","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fhoneypot","docs\u002Fbot-detection\u002F04.checkers\u002F09.honeypot",{"title":476,"path":477,"stem":478},"Known Bad IPs","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fknown-bad-ips","docs\u002Fbot-detection\u002F04.checkers\u002F10.known-bad-ips",{"title":480,"path":481,"stem":482},"Behavior Rate","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fbehavior-rate","docs\u002Fbot-detection\u002F04.checkers\u002F11.behavior-rate",{"title":484,"path":485,"stem":486},"Proxy \u002F ISP \u002F Cookie","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fproxy-isp-cookies","docs\u002Fbot-detection\u002F04.checkers\u002F12.proxy-isp-cookies",{"title":488,"path":489,"stem":490},"Session Coherence","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fsession-coherence","docs\u002Fbot-detection\u002F04.checkers\u002F13.session-coherence",{"title":492,"path":493,"stem":494},"Velocity Fingerprint","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fvelocity-fingerprint","docs\u002Fbot-detection\u002F04.checkers\u002F14.velocity-fingerprint",{"title":496,"path":497,"stem":498},"UA & Header Analysis","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fua-header","docs\u002Fbot-detection\u002F04.checkers\u002F15.ua-header",{"title":500,"path":501,"stem":502},"Geolocation","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fgeolocation","docs\u002Fbot-detection\u002F04.checkers\u002F16.geolocation",{"title":504,"path":505,"stem":506},"Known Bad User-Agents","\u002Fdocs\u002Fbot-detection\u002Fcheckers\u002Fknown-bad-ua","docs\u002Fbot-detection\u002F04.checkers\u002F17.known-bad-ua",{"title":38,"path":508,"stem":509},"\u002Fdocs\u002Fbot-detection\u002Fsecurity","docs\u002Fbot-detection\u002F04.security",{"title":246,"path":511,"stem":512},"\u002Fdocs\u002Fbot-detection\u002Fapi","docs\u002Fbot-detection\u002F05.api",{"title":237,"path":514,"stem":515},"\u002Fdocs\u002Fbot-detection\u002Fconfiguration","docs\u002Fbot-detection\u002F06.configuration",{"title":517,"path":11,"stem":518,"children":519},"Introduction","docs\u002Fgetting-started\u002Findex",[520],{"title":517,"path":11,"stem":518},{"title":27,"path":29,"stem":70,"children":522},[523,524,525,565,566,571,572],{"title":27,"path":29,"stem":70},{"title":14,"path":74,"stem":75},{"title":77,"path":78,"stem":79,"children":526},[527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549],{"title":77,"path":78,"stem":79},{"title":83,"path":84,"stem":85},{"title":87,"path":88,"stem":89},{"title":91,"path":92,"stem":93},{"title":95,"path":96,"stem":97},{"title":99,"path":100,"stem":101},{"title":103,"path":104,"stem":105},{"title":107,"path":108,"stem":109},{"title":111,"path":112,"stem":113},{"title":115,"path":116,"stem":117},{"title":119,"path":120,"stem":121},{"title":123,"path":124,"stem":125},{"title":127,"path":128,"stem":129},{"title":131,"path":132,"stem":133},{"title":135,"path":136,"stem":137},{"title":139,"path":140,"stem":141},{"title":143,"path":144,"stem":145},{"title":147,"path":148,"stem":149},{"title":151,"path":152,"stem":153},{"title":155,"path":156,"stem":157},{"title":159,"path":160,"stem":161},{"title":163,"path":164,"stem":165},{"title":167,"path":168,"stem":169,"children":550},[551,552,553,554,563,564],{"title":167,"path":168,"stem":169},{"title":173,"path":174,"stem":175},{"title":177,"path":178,"stem":179},{"title":181,"path":182,"stem":183,"children":555},[556,557,558,559,560,561,562],{"title":181,"path":182,"stem":183},{"title":187,"path":188,"stem":189},{"title":191,"path":192,"stem":193},{"title":195,"path":196,"stem":197},{"title":199,"path":200,"stem":201},{"title":203,"path":204,"stem":205},{"title":207,"path":208,"stem":209},{"title":147,"path":211,"stem":212},{"title":38,"path":214,"stem":215},{"title":38,"path":217,"stem":218},{"title":220,"path":221,"stem":222,"children":567,"page":53},[568,569,570],{"title":225,"path":226,"stem":227},{"title":229,"path":230,"stem":231},{"title":233,"path":234,"stem":235},{"title":237,"path":238,"stem":239},{"title":241,"path":242,"stem":243,"children":573,"page":53},[574,575,576],{"title":246,"path":247,"stem":248},{"title":250,"path":251,"stem":252},{"title":254,"path":255,"stem":256},{"title":40,"path":42,"stem":578,"children":579},"docs\u002Fshield-base\u002Findex",[580,581,584,588,629,633,637,641],{"title":40,"path":42,"stem":578},{"title":14,"path":582,"stem":583},"\u002Fdocs\u002Fshield-base\u002Fgetting-started","docs\u002Fshield-base\u002F00.getting-started",{"title":585,"path":586,"stem":587},"CLI Reference","\u002Fdocs\u002Fshield-base\u002Fcli","docs\u002Fshield-base\u002F01.cli",{"title":411,"path":589,"stem":590,"children":591},"\u002Fdocs\u002Fshield-base\u002Fdata-sources","docs\u002Fshield-base\u002F02.data-sources\u002Findex",[592,593,597,601,605,609,613,617,621,625],{"title":411,"path":589,"stem":590},{"title":594,"path":595,"stem":596},"BGP \u002F ASN","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fbgp","docs\u002Fshield-base\u002F02.data-sources\u002Fbgp",{"title":598,"path":599,"stem":600},"City Geolocation","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fcity","docs\u002Fshield-base\u002F02.data-sources\u002Fcity",{"title":602,"path":603,"stem":604},"Country Geolocation","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fcountry","docs\u002Fshield-base\u002F02.data-sources\u002Fcountry",{"title":606,"path":607,"stem":608},"Verified Crawlers","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fcrawlers","docs\u002Fshield-base\u002F02.data-sources\u002Fcrawlers",{"title":610,"path":611,"stem":612},"Disposable Emails","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Femail","docs\u002Fshield-base\u002F02.data-sources\u002Femail",{"title":614,"path":615,"stem":616},"FireHOL Threat Intelligence","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Ffirehol","docs\u002Fshield-base\u002F02.data-sources\u002Ffirehol",{"title":618,"path":619,"stem":620},"Proxy Detection","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fproxy","docs\u002Fshield-base\u002F02.data-sources\u002Fproxy",{"title":622,"path":623,"stem":624},"Tor Nodes","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Ftor","docs\u002Fshield-base\u002F02.data-sources\u002Ftor",{"title":626,"path":627,"stem":628},"Suspicious User-Agents","\u002Fdocs\u002Fshield-base\u002Fdata-sources\u002Fuseragent","docs\u002Fshield-base\u002F02.data-sources\u002Fuseragent",{"title":630,"path":631,"stem":632},"Programmatic Usage","\u002Fdocs\u002Fshield-base\u002Fusage","docs\u002Fshield-base\u002F03.usage",{"title":634,"path":635,"stem":636},"Custom Data Sources","\u002Fdocs\u002Fshield-base\u002Fcustom-data-sources","docs\u002Fshield-base\u002F04.custom-data-sources",{"title":638,"path":639,"stem":640},"TypeScript Types","\u002Fdocs\u002Fshield-base\u002Ftypes","docs\u002Fshield-base\u002F05.types",{"title":246,"path":642,"stem":643},"\u002Fdocs\u002Fshield-base\u002Fapi","docs\u002Fshield-base\u002F06.api",{"title":395,"path":48,"stem":645,"children":646},"docs\u002Futils\u002Findex",[647,648,665,698,795],{"title":395,"path":48,"stem":645},{"title":649,"path":650,"stem":651,"children":652,"page":53},"Eslint","\u002Fdocs\u002Futils\u002Feslint","docs\u002Futils\u002Feslint",[653,657,661],{"title":654,"path":655,"stem":656},"React Config","\u002Fdocs\u002Futils\u002Feslint\u002Freact","docs\u002Futils\u002Feslint\u002Freact",{"title":658,"path":659,"stem":660},"TypeScript Config","\u002Fdocs\u002Futils\u002Feslint\u002Ftypescript","docs\u002Futils\u002Feslint\u002Ftypescript",{"title":662,"path":663,"stem":664},"Vue Config","\u002Fdocs\u002Futils\u002Feslint\u002Fvue","docs\u002Futils\u002Feslint\u002Fvue",{"title":666,"path":667,"stem":668,"children":669,"page":53},"Server","\u002Fdocs\u002Futils\u002Fserver","docs\u002Futils\u002Fserver",[670,674,678,682,686,690,694],{"title":671,"path":672,"stem":673},"Encryption","\u002Fdocs\u002Futils\u002Fserver\u002Fencryption","docs\u002Futils\u002Fserver\u002Fencryption",{"title":675,"path":676,"stem":677},"Path Resolver","\u002Fdocs\u002Futils\u002Fserver\u002Fpathresolver","docs\u002Futils\u002Fserver\u002FpathResolver",{"title":679,"path":680,"stem":681},"File Replacements","\u002Fdocs\u002Futils\u002Fserver\u002Freplace","docs\u002Futils\u002Fserver\u002Freplace",{"title":683,"path":684,"stem":685},"run","\u002Fdocs\u002Futils\u002Fserver\u002Frun","docs\u002Futils\u002Fserver\u002Frun",{"title":687,"path":688,"stem":689},"scheduleTask","\u002Fdocs\u002Futils\u002Fserver\u002Fscheduletask","docs\u002Futils\u002Fserver\u002FscheduleTask",{"title":691,"path":692,"stem":693},"spawnRun","\u002Fdocs\u002Futils\u002Fserver\u002Fspawnrun","docs\u002Futils\u002Fserver\u002FspawnRun",{"title":695,"path":696,"stem":697},"uploadCsv","\u002Fdocs\u002Futils\u002Fserver\u002Fuploadcsv","docs\u002Futils\u002Fserver\u002FuploadCsv",{"title":699,"path":700,"stem":701,"children":702,"page":53},"Shared","\u002Fdocs\u002Futils\u002Fshared","docs\u002Futils\u002Fshared",[703,707,711,715,719,723,727,731,735,739,743,747,751,755,759,763,767,771,775,779,783,787,791],{"title":704,"path":705,"stem":706},"BatchQueue","\u002Fdocs\u002Futils\u002Fshared\u002Fbatchqueue","docs\u002Futils\u002Fshared\u002FbatchQueue",{"title":708,"path":709,"stem":710},"capitalize","\u002Fdocs\u002Futils\u002Fshared\u002Fcapitalize","docs\u002Futils\u002Fshared\u002Fcapitalize",{"title":712,"path":713,"stem":714},"chunkProcess","\u002Fdocs\u002Futils\u002Fshared\u002Fchunkprocess","docs\u002Futils\u002Fshared\u002FchunkProcess",{"title":716,"path":717,"stem":718},"cleanObject","\u002Fdocs\u002Futils\u002Fshared\u002Fcleanobject","docs\u002Futils\u002Fshared\u002FcleanObject",{"title":720,"path":721,"stem":722},"createConfigManager","\u002Fdocs\u002Futils\u002Fshared\u002Fconfigurationdefiner","docs\u002Futils\u002Fshared\u002FconfigurationDefiner",{"title":724,"path":725,"stem":726},"debounce","\u002Fdocs\u002Futils\u002Fshared\u002Fdebounce","docs\u002Futils\u002Fshared\u002Fdebounce",{"title":728,"path":729,"stem":730},"ensureArray","\u002Fdocs\u002Futils\u002Fshared\u002Fensurearray","docs\u002Futils\u002Fshared\u002FensureArray",{"title":732,"path":733,"stem":734},"fetchWithRetry","\u002Fdocs\u002Futils\u002Fshared\u002Ffetchwithretry","docs\u002Futils\u002Fshared\u002FfetchWithRetry",{"title":736,"path":737,"stem":738},"filterEmptyValues","\u002Fdocs\u002Futils\u002Fshared\u002Ffilteremptyvalues","docs\u002Futils\u002Fshared\u002FfilterEmptyValues",{"title":740,"path":741,"stem":742},"findStringsInObject","\u002Fdocs\u002Futils\u002Fshared\u002Ffindobjectvalues","docs\u002Futils\u002Fshared\u002FfindObjectValues",{"title":744,"path":745,"stem":746},"fisherYatesShuffle","\u002Fdocs\u002Futils\u002Fshared\u002Ffisheryatesshuffle","docs\u002Futils\u002Fshared\u002FfisherYatesShuffle",{"title":748,"path":749,"stem":750},"getRandomImage","\u002Fdocs\u002Futils\u002Fshared\u002Fgetrandomimage","docs\u002Futils\u002Fshared\u002FgetRandomImage",{"title":752,"path":753,"stem":754},"isObjectHasValues","\u002Fdocs\u002Futils\u002Fshared\u002Fisobjecthasvalues","docs\u002Futils\u002Fshared\u002FisObjectHasValues",{"title":756,"path":757,"stem":758},"isAsyncOrPromise","\u002Fdocs\u002Futils\u002Fshared\u002Fispromise","docs\u002Futils\u002Fshared\u002FisPromise",{"title":760,"path":761,"stem":762},"MiniCache","\u002Fdocs\u002Futils\u002Fshared\u002Fminicache","docs\u002Futils\u002Fshared\u002FminiCache",{"title":764,"path":765,"stem":766},"parseCookies","\u002Fdocs\u002Futils\u002Fshared\u002Fparserawcookies","docs\u002Futils\u002Fshared\u002FparseRawCookies",{"title":768,"path":769,"stem":770},"safeAction","\u002Fdocs\u002Futils\u002Fshared\u002Fpromiselocker","docs\u002Futils\u002Fshared\u002FpromiseLocker",{"title":772,"path":773,"stem":774},"Random","\u002Fdocs\u002Futils\u002Fshared\u002Frandom","docs\u002Futils\u002Fshared\u002Frandom",{"title":776,"path":777,"stem":778},"range","\u002Fdocs\u002Futils\u002Fshared\u002Frange","docs\u002Futils\u002Fshared\u002Frange",{"title":780,"path":781,"stem":782},"rateLimiters","\u002Fdocs\u002Futils\u002Fshared\u002Fratelimiters","docs\u002Futils\u002Fshared\u002FrateLimiters",{"title":784,"path":785,"stem":786},"safeObjectMerge","\u002Fdocs\u002Futils\u002Fshared\u002Fsafemerge","docs\u002Futils\u002Fshared\u002FsafeMerge",{"title":788,"path":789,"stem":790},"textTruncation","\u002Fdocs\u002Futils\u002Fshared\u002Ftexttruncation","docs\u002Futils\u002Fshared\u002FtextTruncation",{"title":792,"path":793,"stem":794},"validateZodSchema","\u002Fdocs\u002Futils\u002Fshared\u002Fvalidatezodschema","docs\u002Futils\u002Fshared\u002FvalidateZodSchema",{"title":796,"path":797,"stem":798,"children":799},"Utility Types","\u002Fdocs\u002Futils\u002Ftypes","docs\u002Futils\u002Ftypes\u002Findex",[800,801,805,809,813,817,821,825,829,833],{"title":796,"path":797,"stem":798},{"title":802,"path":803,"stem":804},"Brand","\u002Fdocs\u002Futils\u002Ftypes\u002Fbrand","docs\u002Futils\u002Ftypes\u002FBrand",{"title":806,"path":807,"stem":808},"DeepPartial","\u002Fdocs\u002Futils\u002Ftypes\u002Fdeeppartial","docs\u002Futils\u002Ftypes\u002FDeepPartial",{"title":810,"path":811,"stem":812},"Merge","\u002Fdocs\u002Futils\u002Ftypes\u002Fmerge","docs\u002Futils\u002Ftypes\u002FMerge",{"title":814,"path":815,"stem":816},"NonNullable","\u002Fdocs\u002Futils\u002Ftypes\u002Fnonnullable","docs\u002Futils\u002Ftypes\u002FNonNullable",{"title":818,"path":819,"stem":820},"Prettify","\u002Fdocs\u002Futils\u002Ftypes\u002Fprettify","docs\u002Futils\u002Ftypes\u002FPrettify",{"title":822,"path":823,"stem":824},"PromiseType","\u002Fdocs\u002Futils\u002Ftypes\u002Fpromisetype","docs\u002Futils\u002Ftypes\u002FPromiseType",{"title":826,"path":827,"stem":828},"RequireKeys","\u002Fdocs\u002Futils\u002Ftypes\u002Frequirekeys","docs\u002Futils\u002Ftypes\u002FRequireKeys",{"title":830,"path":831,"stem":832},"StandardResponse","\u002Fdocs\u002Futils\u002Ftypes\u002Fstandardresponse","docs\u002Futils\u002Ftypes\u002FStandardResponse",{"title":834,"path":835,"stem":836},"ValueOf","\u002Fdocs\u002Futils\u002Ftypes\u002Fvalueof","docs\u002Futils\u002Ftypes\u002FValueOf",{"id":4,"extension":5,"links":838,"meta":849,"stem":62,"__hash__":63},[839,847,848],{"nested":8,"label":9,"icon":10,"to":11,"children":840},[841,842,843,844,845,846],{"label":14,"icon":15,"to":11,"description":16,"github":17,"badge":18},{"label":20,"icon":21,"to":22,"description":23,"github":24,"badge":25},{"label":27,"icon":28,"to":29,"description":30,"github":31,"badge":25},{"label":33,"icon":34,"to":35,"description":36,"github":37,"badge":38},{"label":40,"icon":41,"to":42,"description":43,"github":44,"badge":38},{"label":46,"icon":47,"to":48,"description":49,"github":50,"badge":51},{"nested":53,"label":54,"icon":55,"to":56},{"nested":53,"label":58,"icon":59,"to":60},{},{"id":851,"title":135,"body":852,"description":2260,"extension":2261,"icon":21,"meta":2262,"module":2263,"navigation":8,"path":136,"rawbody":2264,"seo":2265,"stem":137,"__hash__":2266},"docs\u002Fdocs\u002Fiam\u002F01.essentials\u002F13.hmac.md",{"type":853,"value":854,"toc":2246},"minimark",[855,873,876,887,890,895,902,907,996,1000,1003,1013,1024,1030,1048,1050,1054,1057,1165,1175,1177,1181,1198,1226,1234,1236,1240,1243,1844,1855,1857,1861,1868,1954,1971,1973,1977,1980,2014,2031,2036,2038,2042,2056,2109,2124,2126,2130,2136,2175,2183,2185,2189,2242],[856,857,858,859,866,867,872],"p",{},"The IAM service supports an optional ",[860,861,865],"a",{"href":862,"rel":863},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FHMAC",[864],"nofollow","HMAC"," authentication layer for service-to-service communication. When enabled, every inbound request must carry four headers: a client identifier, a millisecond timestamp, a unique request ID, and an HMAC-SHA256 signature computed from a shared secret. The service verifies the signature using a constant-time comparison, rejects replayed requests via an ",[860,868,871],{"href":869,"rel":870},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCache_replacement_policies#Least_recently_used_(LRU)",[864],"LRU"," nonce cache, and enforces a configurable clock-skew window.",[856,874,875],{},"This layer protects IAM endpoints from unauthorized access by services on the same private network. Without HMAC, any service that can reach the IAM port can call its API. With HMAC, only services that possess the shared secret can produce valid signatures.",[877,878,879],"note",{},[856,880,881,882,886],{},"HMAC authentication is optional. Configure it in ",[883,884,885],"code",{},"service.Hmac"," only when you have internal services that call IAM endpoints directly without going through the user-facing client. User-facing requests (browser to IAM) use cookie-based JWT authentication instead.",[888,889],"hr",{},[891,892,894],"h2",{"id":893},"how-it-works","How it works",[856,896,897,898,901],{},"The ",[883,899,900],{},"hmacAuth"," middleware runs early in the Express middleware chain, before JSON body parsing and cookie parsing. It intercepts every inbound request and validates the four required headers before allowing the request to proceed.",[903,904,906],"h3",{"id":905},"required-headers","Required headers",[908,909,910,926],"table",{},[911,912,913],"thead",{},[914,915,916,920,923],"tr",{},[917,918,919],"th",{},"Header",[917,921,922],{},"Type",[917,924,925],{},"Description",[927,928,929,949,968,982],"tbody",{},[914,930,931,937,942],{},[932,933,934],"td",{},[883,935,936],{},"X-Client-Id",[932,938,939],{},[883,940,941],{},"string",[932,943,944,945,948],{},"The identifier of the calling service. Must match the ",[883,946,947],{},"clientId"," value in the IAM configuration.",[914,950,951,956,960],{},[932,952,953],{},[883,954,955],{},"X-Timestamp",[932,957,958],{},[883,959,941],{},[932,961,962,963,967],{},"The client's current time in ",[964,965,966],"strong",{},"milliseconds"," since the Unix epoch. Used for clock-skew validation.",[914,969,970,975,979],{},[932,971,972],{},[883,973,974],{},"X-Request-ID",[932,976,977],{},[883,978,941],{},[932,980,981],{},"A unique identifier for this specific request. Used for replay detection. Must never be reused.",[914,983,984,989,993],{},[932,985,986],{},[883,987,988],{},"X-Signature",[932,990,991],{},[883,992,941],{},[932,994,995],{},"The hex-encoded HMAC-SHA256 signature of the request, computed from the shared secret.",[903,997,999],{"id":998},"signature-computation","Signature computation",[856,1001,1002],{},"The signature is computed over a colon-separated string containing the client ID, timestamp, HTTP method, full request URL (including query string), and the request ID:",[1004,1005,1010],"pre",{"className":1006,"code":1008,"language":1009},[1007],"language-text","base = \"{X-Client-Id}:{X-Timestamp}:{METHOD}:{originalUrl}:{X-Request-ID}\"\nsignature = HMAC-SHA256(sharedSecret, base).hex()\n","text",[883,1011,1008],{"__ignoreMap":1012},"",[856,1014,1015,1016,1019,1020,1023],{},"For example, a POST request to ",[883,1017,1018],{},"\u002Fauth\u002Fuser\u002Frefresh-session"," from the ",[883,1021,1022],{},"billing-service"," client:",[1004,1025,1028],{"className":1026,"code":1027,"language":1009},[1007],"base = \"billing-service:1712419200000:POST:\u002Fauth\u002Fuser\u002Frefresh-session:550e8400-e29b-41d4-a716-446655440000\"\nsignature = HMAC-SHA256(\"my-shared-secret\", base).hex()\n",[883,1029,1027],{"__ignoreMap":1012},[1031,1032,1033],"warning",{},[856,1034,1035,1036,1039,1040,1043,1044,1047],{},"The signature covers the ",[883,1037,1038],{},"originalUrl",", not just the path. This means query parameters are included in the signed payload. A request to ",[883,1041,1042],{},"\u002Fapi\u002Fusers?page=2"," produces a different signature than ",[883,1045,1046],{},"\u002Fapi\u002Fusers?page=3",". This prevents an attacker from modifying query parameters on a captured request.",[888,1049],{},[891,1051,1053],{"id":1052},"verification-flow","Verification flow",[856,1055,1056],{},"The middleware performs five checks in sequence. The first failure short-circuits the chain and returns HTTP 401 with a reason string.",[1058,1059,1061,1066,1083,1087,1099,1103,1120,1123,1127,1136,1142,1146,1156],"steps",{"level":1060},"4",[1062,1063,1065],"h4",{"id":1064},"header-presence","Header presence",[856,1067,1068,1069,1071,1072,1071,1074,1071,1076,1078,1079,1082],{},"All four headers (",[883,1070,936],{},", ",[883,1073,955],{},[883,1075,988],{},[883,1077,974],{},") must be present. If any is missing, the request is rejected with ",[883,1080,1081],{},"'Missing auth headers'",".",[1062,1084,1086],{"id":1085},"client-identity","Client identity",[856,1088,897,1089,1091,1092,1095,1096,1082],{},[883,1090,936],{}," value must exactly match ",[883,1093,1094],{},"service.Hmac.clientId"," from the configuration. If it does not match, the request is rejected with ",[883,1097,1098],{},"'Unknown client'",[1062,1100,1102],{"id":1101},"clock-skew-validation","Clock-skew validation",[856,1104,1105,1106,1109,1110,1112,1113,1116,1117,1082],{},"The absolute difference between the server's current time (",[883,1107,1108],{},"Date.now()",") and the ",[883,1111,955],{}," value must be less than or equal to ",[883,1114,1115],{},"maxClockSkew"," milliseconds. If the timestamp is outside this window, the request is rejected with ",[883,1118,1119],{},"'Stale timestamp'",[856,1121,1122],{},"This check serves two purposes: it prevents old captured requests from being replayed after the skew window expires, and it rejects requests with timestamps far in the future (which could indicate clock manipulation).",[1062,1124,1126],{"id":1125},"replay-detection","Replay detection",[856,1128,897,1129,1131,1132,1135],{},[883,1130,974],{}," is checked against an LRU nonce cache. If the ID already exists in the cache, the request is rejected with ",[883,1133,1134],{},"'Replay detected'",". This catches an attacker replaying a valid request within the clock-skew window.",[856,1137,1138,1139,1141],{},"The nonce cache holds up to 5,000 entries with a TTL equal to ",[883,1140,1115],{},". Once the TTL expires, the nonce is evicted and a request with the same ID would pass the replay check, but it would then fail the clock-skew check because the original timestamp is now outside the window.",[1062,1143,1145],{"id":1144},"timing-safe-signature-comparison","Timing-safe signature comparison",[856,1147,1148,1149,1151,1152,1155],{},"The middleware recomputes the signature from the shared secret and the same base string format. It then compares the expected signature against the received ",[883,1150,988],{}," using ",[883,1153,1154],{},"crypto.timingSafeEqual"," on the hex-decoded buffers.",[856,1157,1158,1159,1164],{},"Before comparing, it verifies that both buffers are the same length. If the lengths differ, the request is rejected immediately (a length mismatch is always invalid). The constant-time comparison prevents ",[860,1160,1163],{"href":1161,"rel":1162},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FTiming_attack",[864],"timing attacks"," that could leak information about the correct signature byte-by-byte.",[856,1166,1167,1168,1170,1171,1174],{},"On success, the request ID is added to the nonce cache with a TTL of ",[883,1169,1115],{},", and the middleware calls ",[883,1172,1173],{},"next()"," to proceed to the route handler.",[888,1176],{},[891,1178,1180],{"id":1179},"health-check-bypass","Health check bypass",[856,1182,1183,1186,1187,1071,1190,1193,1194,1197],{},[883,1184,1185],{},"GET \u002Fhealth"," requests from localhost (",[883,1188,1189],{},"127.0.0.1",[883,1191,1192],{},"::1",", or ",[883,1195,1196],{},"::ffff:127.0.0.1",") bypass HMAC validation entirely. This allows container orchestrators (Docker, Kubernetes) to run health checks without needing access to the shared secret.",[1004,1199,1203],{"className":1200,"code":1201,"language":1202,"meta":1012,"style":1012},"language-ts shiki shiki-themes light-plus light-plus dracula","\u002F\u002F These requests skip HMAC validation:\n\u002F\u002F GET http:\u002F\u002F127.0.0.1:10000\u002Fhealth\n\u002F\u002F GET http:\u002F\u002F[::1]:10000\u002Fhealth\n","ts",[883,1204,1205,1214,1220],{"__ignoreMap":1012},[1206,1207,1210],"span",{"class":1208,"line":1209},"line",1,[1206,1211,1213],{"class":1212},"sghk6","\u002F\u002F These requests skip HMAC validation:\n",[1206,1215,1217],{"class":1208,"line":1216},2,[1206,1218,1219],{"class":1212},"\u002F\u002F GET http:\u002F\u002F127.0.0.1:10000\u002Fhealth\n",[1206,1221,1223],{"class":1208,"line":1222},3,[1206,1224,1225],{"class":1212},"\u002F\u002F GET http:\u002F\u002F[::1]:10000\u002Fhealth\n",[1031,1227,1228],{},[856,1229,1230,1231,1233],{},"Only local health checks are exempt. A ",[883,1232,1185],{}," request from any non-local IP is subject to the full HMAC validation when the middleware is enabled.",[888,1235],{},[891,1237,1239],{"id":1238},"signing-requests-from-a-calling-service","Signing requests from a calling service",[856,1241,1242],{},"The calling service must compute the signature using the same base string format and the same shared secret. Here is a complete implementation:",[1004,1244,1246],{"className":1200,"code":1245,"language":1202,"meta":1012,"style":1012},"import crypto from 'node:crypto'\n\nfunction signRequest(\n  method: string,\n  url: string,\n  secret: string,\n  clientId: string\n): Record\u003Cstring, string> {\n  const timestamp = Date.now().toString()\n  const requestId = crypto.randomUUID()\n  const base = `${clientId}:${timestamp}:${method}:${url}:${requestId}`\n  const signature = crypto.createHmac('sha256', secret).update(base).digest('hex')\n\n  return {\n    'X-Client-Id': clientId,\n    'X-Timestamp': timestamp,\n    'X-Signature': signature,\n    'X-Request-ID': requestId,\n  }\n}\n\n\u002F\u002F Usage\nconst headers = signRequest(\n  'POST',\n  '\u002Fauth\u002Fuser\u002Frefresh-session',\n  process.env.HMAC_SECRET!,\n  'billing-service'\n)\n\nconst response = await fetch('https:\u002F\u002Fiam.internal\u002Fauth\u002Fuser\u002Frefresh-session', {\n  method: 'POST',\n  headers: {\n    ...headers,\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({ token: refreshToken }),\n})\n",[883,1247,1248,1272,1277,1291,1309,1321,1333,1344,1367,1397,1416,1476,1537,1542,1551,1569,1584,1599,1614,1620,1626,1631,1637,1652,1665,1676,1698,1707,1712,1717,1745,1760,1770,1781,1802,1808,1838],{"__ignoreMap":1012},[1206,1249,1250,1254,1258,1261,1265,1269],{"class":1208,"line":1209},[1206,1251,1253],{"class":1252},"sZ328","import",[1206,1255,1257],{"class":1256},"sjsA6"," crypto",[1206,1259,1260],{"class":1252}," from",[1206,1262,1264],{"class":1263},"sFkSl"," '",[1206,1266,1268],{"class":1267},"sFB1V","node:crypto",[1206,1270,1271],{"class":1263},"'\n",[1206,1273,1274],{"class":1208,"line":1216},[1206,1275,1276],{"emptyLinePlaceholder":8},"\n",[1206,1278,1279,1283,1287],{"class":1208,"line":1222},[1206,1280,1282],{"class":1281},"sl46w","function",[1206,1284,1286],{"class":1285},"sHOzp"," signRequest",[1206,1288,1290],{"class":1289},"sDd4n","(\n",[1206,1292,1294,1298,1302,1306],{"class":1208,"line":1293},4,[1206,1295,1297],{"class":1296},"sygFZ","  method",[1206,1299,1301],{"class":1300},"saOXh",":",[1206,1303,1305],{"class":1304},"sFs1U"," string",[1206,1307,1308],{"class":1289},",\n",[1206,1310,1312,1315,1317,1319],{"class":1208,"line":1311},5,[1206,1313,1314],{"class":1296},"  url",[1206,1316,1301],{"class":1300},[1206,1318,1305],{"class":1304},[1206,1320,1308],{"class":1289},[1206,1322,1324,1327,1329,1331],{"class":1208,"line":1323},6,[1206,1325,1326],{"class":1296},"  secret",[1206,1328,1301],{"class":1300},[1206,1330,1305],{"class":1304},[1206,1332,1308],{"class":1289},[1206,1334,1336,1339,1341],{"class":1208,"line":1335},7,[1206,1337,1338],{"class":1296},"  clientId",[1206,1340,1301],{"class":1300},[1206,1342,1343],{"class":1304}," string\n",[1206,1345,1347,1350,1352,1355,1358,1360,1362,1364],{"class":1208,"line":1346},8,[1206,1348,1349],{"class":1289},")",[1206,1351,1301],{"class":1300},[1206,1353,1354],{"class":1304}," Record",[1206,1356,1357],{"class":1289},"\u003C",[1206,1359,941],{"class":1304},[1206,1361,1071],{"class":1289},[1206,1363,941],{"class":1304},[1206,1365,1366],{"class":1289},"> {\n",[1206,1368,1370,1373,1377,1380,1383,1385,1388,1391,1394],{"class":1208,"line":1369},9,[1206,1371,1372],{"class":1281},"  const",[1206,1374,1376],{"class":1375},"s3JHE"," timestamp",[1206,1378,1379],{"class":1300}," =",[1206,1381,1382],{"class":1256}," Date",[1206,1384,1082],{"class":1289},[1206,1386,1387],{"class":1285},"now",[1206,1389,1390],{"class":1289},"().",[1206,1392,1393],{"class":1285},"toString",[1206,1395,1396],{"class":1289},"()\n",[1206,1398,1400,1402,1405,1407,1409,1411,1414],{"class":1208,"line":1399},10,[1206,1401,1372],{"class":1281},[1206,1403,1404],{"class":1375}," requestId",[1206,1406,1379],{"class":1300},[1206,1408,1257],{"class":1256},[1206,1410,1082],{"class":1289},[1206,1412,1413],{"class":1285},"randomUUID",[1206,1415,1396],{"class":1289},[1206,1417,1419,1421,1424,1426,1429,1432,1434,1437,1439,1441,1444,1446,1448,1450,1453,1455,1457,1459,1462,1464,1466,1468,1471,1473],{"class":1208,"line":1418},11,[1206,1420,1372],{"class":1281},[1206,1422,1423],{"class":1375}," base",[1206,1425,1379],{"class":1300},[1206,1427,1428],{"class":1267}," `",[1206,1430,1431],{"class":1281},"${",[1206,1433,947],{"class":1256},[1206,1435,1436],{"class":1281},"}",[1206,1438,1301],{"class":1267},[1206,1440,1431],{"class":1281},[1206,1442,1443],{"class":1256},"timestamp",[1206,1445,1436],{"class":1281},[1206,1447,1301],{"class":1267},[1206,1449,1431],{"class":1281},[1206,1451,1452],{"class":1256},"method",[1206,1454,1436],{"class":1281},[1206,1456,1301],{"class":1267},[1206,1458,1431],{"class":1281},[1206,1460,1461],{"class":1256},"url",[1206,1463,1436],{"class":1281},[1206,1465,1301],{"class":1267},[1206,1467,1431],{"class":1281},[1206,1469,1470],{"class":1256},"requestId",[1206,1472,1436],{"class":1281},[1206,1474,1475],{"class":1267},"`\n",[1206,1477,1479,1481,1484,1486,1488,1490,1493,1496,1499,1502,1504,1506,1509,1512,1515,1517,1520,1522,1525,1527,1529,1532,1534],{"class":1208,"line":1478},12,[1206,1480,1372],{"class":1281},[1206,1482,1483],{"class":1375}," signature",[1206,1485,1379],{"class":1300},[1206,1487,1257],{"class":1256},[1206,1489,1082],{"class":1289},[1206,1491,1492],{"class":1285},"createHmac",[1206,1494,1495],{"class":1289},"(",[1206,1497,1498],{"class":1263},"'",[1206,1500,1501],{"class":1267},"sha256",[1206,1503,1498],{"class":1263},[1206,1505,1071],{"class":1289},[1206,1507,1508],{"class":1256},"secret",[1206,1510,1511],{"class":1289},").",[1206,1513,1514],{"class":1285},"update",[1206,1516,1495],{"class":1289},[1206,1518,1519],{"class":1256},"base",[1206,1521,1511],{"class":1289},[1206,1523,1524],{"class":1285},"digest",[1206,1526,1495],{"class":1289},[1206,1528,1498],{"class":1263},[1206,1530,1531],{"class":1267},"hex",[1206,1533,1498],{"class":1263},[1206,1535,1536],{"class":1289},")\n",[1206,1538,1540],{"class":1208,"line":1539},13,[1206,1541,1276],{"emptyLinePlaceholder":8},[1206,1543,1545,1548],{"class":1208,"line":1544},14,[1206,1546,1547],{"class":1252},"  return",[1206,1549,1550],{"class":1289}," {\n",[1206,1552,1554,1557,1559,1561,1564,1567],{"class":1208,"line":1553},15,[1206,1555,1556],{"class":1263},"    '",[1206,1558,936],{"class":1267},[1206,1560,1498],{"class":1263},[1206,1562,1301],{"class":1563},"s34zl",[1206,1565,1566],{"class":1256}," clientId",[1206,1568,1308],{"class":1289},[1206,1570,1572,1574,1576,1578,1580,1582],{"class":1208,"line":1571},16,[1206,1573,1556],{"class":1263},[1206,1575,955],{"class":1267},[1206,1577,1498],{"class":1263},[1206,1579,1301],{"class":1563},[1206,1581,1376],{"class":1256},[1206,1583,1308],{"class":1289},[1206,1585,1587,1589,1591,1593,1595,1597],{"class":1208,"line":1586},17,[1206,1588,1556],{"class":1263},[1206,1590,988],{"class":1267},[1206,1592,1498],{"class":1263},[1206,1594,1301],{"class":1563},[1206,1596,1483],{"class":1256},[1206,1598,1308],{"class":1289},[1206,1600,1602,1604,1606,1608,1610,1612],{"class":1208,"line":1601},18,[1206,1603,1556],{"class":1263},[1206,1605,974],{"class":1267},[1206,1607,1498],{"class":1263},[1206,1609,1301],{"class":1563},[1206,1611,1404],{"class":1256},[1206,1613,1308],{"class":1289},[1206,1615,1617],{"class":1208,"line":1616},19,[1206,1618,1619],{"class":1289},"  }\n",[1206,1621,1623],{"class":1208,"line":1622},20,[1206,1624,1625],{"class":1289},"}\n",[1206,1627,1629],{"class":1208,"line":1628},21,[1206,1630,1276],{"emptyLinePlaceholder":8},[1206,1632,1634],{"class":1208,"line":1633},22,[1206,1635,1636],{"class":1212},"\u002F\u002F Usage\n",[1206,1638,1640,1643,1646,1648,1650],{"class":1208,"line":1639},23,[1206,1641,1642],{"class":1281},"const",[1206,1644,1645],{"class":1375}," headers",[1206,1647,1379],{"class":1300},[1206,1649,1286],{"class":1285},[1206,1651,1290],{"class":1289},[1206,1653,1655,1658,1661,1663],{"class":1208,"line":1654},24,[1206,1656,1657],{"class":1263},"  '",[1206,1659,1660],{"class":1267},"POST",[1206,1662,1498],{"class":1263},[1206,1664,1308],{"class":1289},[1206,1666,1668,1670,1672,1674],{"class":1208,"line":1667},25,[1206,1669,1657],{"class":1263},[1206,1671,1018],{"class":1267},[1206,1673,1498],{"class":1263},[1206,1675,1308],{"class":1289},[1206,1677,1679,1682,1684,1687,1689,1693,1696],{"class":1208,"line":1678},26,[1206,1680,1681],{"class":1256},"  process",[1206,1683,1082],{"class":1289},[1206,1685,1686],{"class":1256},"env",[1206,1688,1082],{"class":1289},[1206,1690,1692],{"class":1691},"sPzPf","HMAC_SECRET",[1206,1694,1695],{"class":1300},"!",[1206,1697,1308],{"class":1289},[1206,1699,1701,1703,1705],{"class":1208,"line":1700},27,[1206,1702,1657],{"class":1263},[1206,1704,1022],{"class":1267},[1206,1706,1271],{"class":1263},[1206,1708,1710],{"class":1208,"line":1709},28,[1206,1711,1536],{"class":1289},[1206,1713,1715],{"class":1208,"line":1714},29,[1206,1716,1276],{"emptyLinePlaceholder":8},[1206,1718,1720,1722,1725,1727,1730,1733,1735,1737,1740,1742],{"class":1208,"line":1719},30,[1206,1721,1642],{"class":1281},[1206,1723,1724],{"class":1375}," response",[1206,1726,1379],{"class":1300},[1206,1728,1729],{"class":1252}," await",[1206,1731,1732],{"class":1285}," fetch",[1206,1734,1495],{"class":1289},[1206,1736,1498],{"class":1263},[1206,1738,1739],{"class":1267},"https:\u002F\u002Fiam.internal\u002Fauth\u002Fuser\u002Frefresh-session",[1206,1741,1498],{"class":1263},[1206,1743,1744],{"class":1289},", {\n",[1206,1746,1748,1750,1752,1754,1756,1758],{"class":1208,"line":1747},31,[1206,1749,1297],{"class":1256},[1206,1751,1301],{"class":1563},[1206,1753,1264],{"class":1263},[1206,1755,1660],{"class":1267},[1206,1757,1498],{"class":1263},[1206,1759,1308],{"class":1289},[1206,1761,1763,1766,1768],{"class":1208,"line":1762},32,[1206,1764,1765],{"class":1256},"  headers",[1206,1767,1301],{"class":1563},[1206,1769,1550],{"class":1289},[1206,1771,1773,1776,1779],{"class":1208,"line":1772},33,[1206,1774,1775],{"class":1300},"    ...",[1206,1777,1778],{"class":1256},"headers",[1206,1780,1308],{"class":1289},[1206,1782,1784,1786,1789,1791,1793,1795,1798,1800],{"class":1208,"line":1783},34,[1206,1785,1556],{"class":1263},[1206,1787,1788],{"class":1267},"Content-Type",[1206,1790,1498],{"class":1263},[1206,1792,1301],{"class":1563},[1206,1794,1264],{"class":1263},[1206,1796,1797],{"class":1267},"application\u002Fjson",[1206,1799,1498],{"class":1263},[1206,1801,1308],{"class":1289},[1206,1803,1805],{"class":1208,"line":1804},35,[1206,1806,1807],{"class":1289},"  },\n",[1206,1809,1811,1814,1816,1819,1821,1824,1827,1830,1832,1835],{"class":1208,"line":1810},36,[1206,1812,1813],{"class":1256},"  body",[1206,1815,1301],{"class":1563},[1206,1817,1818],{"class":1691}," JSON",[1206,1820,1082],{"class":1289},[1206,1822,1823],{"class":1285},"stringify",[1206,1825,1826],{"class":1289},"({ ",[1206,1828,1829],{"class":1256},"token",[1206,1831,1301],{"class":1563},[1206,1833,1834],{"class":1256}," refreshToken",[1206,1836,1837],{"class":1289}," }),\n",[1206,1839,1841],{"class":1208,"line":1840},37,[1206,1842,1843],{"class":1289},"})\n",[1031,1845,1846],{},[856,1847,897,1848,1850,1851,1854],{},[883,1849,974],{}," must be globally unique per request. Use ",[883,1852,1853],{},"crypto.randomUUID()"," or a similar UUID generator. Reusing a request ID within the clock-skew window triggers the replay detection and the request is rejected.",[888,1856],{},[891,1858,1860],{"id":1859},"rejection-handling","Rejection handling",[856,1862,1863,1864,1867],{},"When HMAC validation fails, the ",[883,1865,1866],{},"reject"," function sends an HTTP 401 response with the reason string as the body. It also logs the rejection with the client ID for audit purposes.",[908,1869,1870,1880],{},[911,1871,1872],{},[914,1873,1874,1877],{},[917,1875,1876],{},"Reason",[917,1878,1879],{},"Cause",[927,1881,1882,1901,1915,1930,1942],{},[914,1883,1884,1889],{},[932,1885,1886],{},[883,1887,1888],{},"Missing auth headers",[932,1890,1891,1892,1071,1894,1071,1896,1071,1898,1900],{},"One or more required headers (",[883,1893,936],{},[883,1895,955],{},[883,1897,988],{},[883,1899,974],{},") are absent",[914,1902,1903,1908],{},[932,1904,1905],{},[883,1906,1907],{},"Unknown client",[932,1909,897,1910,1912,1913],{},[883,1911,936],{}," does not match the configured ",[883,1914,947],{},[914,1916,1917,1922],{},[932,1918,1919],{},[883,1920,1921],{},"Stale timestamp",[932,1923,897,1924,1926,1927,1929],{},[883,1925,955],{}," is outside the ",[883,1928,1115],{}," window",[914,1931,1932,1937],{},[932,1933,1934],{},[883,1935,1936],{},"Replay detected",[932,1938,897,1939,1941],{},[883,1940,974],{}," was already used within the nonce cache TTL",[914,1943,1944,1949],{},[932,1945,1946],{},[883,1947,1948],{},"Buffer Doesn't match",[932,1950,1951,1952],{},"The recomputed HMAC signature does not match ",[883,1953,988],{},[856,1955,1956,1957,1960,1961,1964,1965,1960,1968,1082],{},"Every rejection is logged at ",[883,1958,1959],{},"warn"," level with ",[883,1962,1963],{},"{ Authorized: false, reason, clientId }",". Successful validations are logged at ",[883,1966,1967],{},"info",[883,1969,1970],{},"{ Authorized: true, ClientID, Reason: 'Match' }",[888,1972],{},[891,1974,1976],{"id":1975},"rotating-the-shared-secret","Rotating the shared secret",[856,1978,1979],{},"To rotate the shared secret without downtime, update the services in the correct order:",[1058,1981,1982,1986,1993,1997,2003,2007],{"level":1060},[1062,1983,1985],{"id":1984},"update-the-iam-service","Update the IAM service",[856,1987,1988,1989,1992],{},"Set the new ",[883,1990,1991],{},"sharedSecret"," in the IAM configuration and restart the service. The old secret is immediately invalid.",[1062,1994,1996],{"id":1995},"update-calling-services","Update calling services",[856,1998,1999,2000,2002],{},"Deploy the updated ",[883,2001,1991],{}," to all calling services. Each service starts signing with the new secret immediately.",[1062,2004,2006],{"id":2005},"monitor-for-failures","Monitor for failures",[856,2008,2009,2010,2013],{},"Watch the IAM logs for HMAC rejection entries (",[883,2011,2012],{},"reason: 'Buffer Doesn't match'","). These indicate a calling service is still using the old secret. Once no failures appear, the rotation is complete.",[2015,2016,2017],"tip",{},[856,2018,2019,2020,1071,2025,2030],{},"Use a secrets manager (",[860,2021,2024],{"href":2022,"rel":2023},"https:\u002F\u002Faws.amazon.com\u002Fsecrets-manager\u002F",[864],"AWS Secrets Manager",[860,2026,2029],{"href":2027,"rel":2028},"https:\u002F\u002Fwww.vaultproject.io\u002F",[864],"HashiCorp Vault",", or environment variables injected by your orchestrator) to distribute the shared secret. Never hard-code it or commit it to version control.",[1031,2032,2033],{},[856,2034,2035],{},"There is no grace period or dual-key support during rotation. All calling services must be updated before or immediately after the IAM service restarts. Plan the rotation during a maintenance window or use a rolling deployment strategy where the IAM service is the last to restart.",[888,2037],{},[891,2039,2041],{"id":2040},"middleware-mounting","Middleware mounting",[856,2043,2044,2045,2047,2048,2051,2052,2055],{},"The HMAC middleware is conditionally mounted in the Express application based on the ",[883,2046,885],{}," configuration. When the ",[883,2049,2050],{},"Hmac"," block is not present (or ",[883,2053,2054],{},"service"," is undefined), the middleware is skipped entirely and all requests proceed without signature validation.",[1004,2057,2059],{"className":1200,"code":2058,"language":1202,"meta":1012,"style":1012},"\u002F\u002F From the service bootstrap (simplified)\nif (config.service?.Hmac) {\n  app.use(hmacAuth)\n}\n",[883,2060,2061,2066,2089,2105],{"__ignoreMap":1012},[1206,2062,2063],{"class":1208,"line":1209},[1206,2064,2065],{"class":1212},"\u002F\u002F From the service bootstrap (simplified)\n",[1206,2067,2068,2071,2074,2077,2079,2081,2084,2086],{"class":1208,"line":1216},[1206,2069,2070],{"class":1252},"if",[1206,2072,2073],{"class":1289}," (",[1206,2075,2076],{"class":1256},"config",[1206,2078,1082],{"class":1289},[1206,2080,2054],{"class":1256},[1206,2082,2083],{"class":1289},"?.",[1206,2085,2050],{"class":1256},[1206,2087,2088],{"class":1289},") {\n",[1206,2090,2091,2094,2096,2099,2101,2103],{"class":1208,"line":1222},[1206,2092,2093],{"class":1256},"  app",[1206,2095,1082],{"class":1289},[1206,2097,2098],{"class":1285},"use",[1206,2100,1495],{"class":1289},[1206,2102,900],{"class":1256},[1206,2104,1536],{"class":1289},[1206,2106,2107],{"class":1208,"line":1293},[1206,2108,1625],{"class":1289},[856,2110,2111,2112,2115,2116,2119,2120,2123],{},"The middleware is mounted ",[964,2113,2114],{},"before"," ",[883,2117,2118],{},"express.json()"," and ",[883,2121,2122],{},"cookieParser()",", meaning it runs before the request body is parsed. This is intentional: if the signature is invalid, the service rejects the request without spending resources on body parsing.",[888,2125],{},[891,2127,2129],{"id":2128},"configuration-reference","Configuration reference",[856,2131,2132,2133,2135],{},"All HMAC settings live under ",[883,2134,885],{}," in the configuration.",[2137,2138,2139,2147,2161],"field-group",{},[2140,2141,2144],"field",{"name":2142,"type":941,":required":2143},"service.Hmac.sharedSecret","true",[856,2145,2146],{},"The shared secret key used to compute and verify HMAC-SHA256 signatures. Must be identical on the IAM service and all calling services. Use a cryptographically random string of at least 32 characters.",[2140,2148,2149],{"name":1094,"type":941,":required":2143},[856,2150,2151,2152,2154,2155,1071,2158,1511],{},"The expected client identifier. Every request's ",[883,2153,936],{}," header must exactly match this value. Use a descriptive name for the calling service (e.g. ",[883,2156,2157],{},"'billing-service'",[883,2159,2160],{},"'notification-worker'",[2140,2162,2166],{"name":2163,"type":2164,"default":2165},"service.Hmac.maxClockSkew","number","300000",[856,2167,2168,2169,2171,2172,2174],{},"Maximum allowed difference in milliseconds between the server's current time and the request's ",[883,2170,955],{},". Requests outside this window are rejected with ",[883,2173,1119],{},". The default is 300,000 ms (5 minutes). Lower values strengthen replay protection but require tighter clock synchronization between services.",[2015,2176,2177],{},[856,2178,2179,2180,2182],{},"If your services run in containers with NTP synchronization, a ",[883,2181,1115],{}," of 30,000 ms (30 seconds) is a reasonable starting point. Increase it only if you observe legitimate rejections due to clock drift.",[888,2184],{},[891,2186,2188],{"id":2187},"summary","Summary",[908,2190,2191,2201],{},[911,2192,2193],{},[914,2194,2195,2198],{},[917,2196,2197],{},"System",[917,2199,2200],{},"Integration point",[927,2202,2203,2213,2223,2232],{},[914,2204,2205,2210],{},[932,2206,2207],{},[860,2208,2209],{"href":251},"Middleware chain",[932,2211,2212],{},"HMAC runs before body parsing and cookie parsing, so invalid requests are rejected with minimal resource consumption",[914,2214,2215,2220],{},[932,2216,2217],{},[860,2218,2219],{"href":148},"Rate limiting",[932,2221,2222],{},"HMAC rejections do not consume rate limit tokens because the middleware rejects before reaching the rate limiter",[914,2224,2225,2229],{},[932,2226,2227],{},[860,2228,143],{"href":144},[932,2230,2231],{},"Every HMAC validation (success or failure) is logged with the client ID, enabling audit trails for inter-service calls",[914,2233,2234,2237],{},[932,2235,2236],{},"Health checks",[932,2238,2239,2241],{},[883,2240,1185],{}," from localhost bypasses HMAC, allowing container health probes without credentials",[2243,2244,2245],"style",{},"html pre.shiki code .sghk6, html code.shiki .sghk6{--shiki-light:#008000;--shiki-default:#008000;--shiki-dark:#6272A4}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sZ328, html code.shiki .sZ328{--shiki-light:#AF00DB;--shiki-default:#AF00DB;--shiki-dark:#FF79C6}html pre.shiki code .sjsA6, html code.shiki .sjsA6{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#F8F8F2}html pre.shiki code .sFkSl, html code.shiki .sFkSl{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#E9F284}html pre.shiki code .sFB1V, html code.shiki .sFB1V{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#F1FA8C}html pre.shiki code .sl46w, html code.shiki .sl46w{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#FF79C6}html pre.shiki code .sHOzp, html code.shiki .sHOzp{--shiki-light:#795E26;--shiki-default:#795E26;--shiki-dark:#50FA7B}html pre.shiki code .sDd4n, html code.shiki .sDd4n{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#F8F8F2}html pre.shiki code .sygFZ, html code.shiki .sygFZ{--shiki-light:#001080;--shiki-light-font-style:inherit;--shiki-default:#001080;--shiki-default-font-style:inherit;--shiki-dark:#FFB86C;--shiki-dark-font-style:italic}html pre.shiki code .saOXh, html code.shiki .saOXh{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#FF79C6}html pre.shiki code .sFs1U, html code.shiki .sFs1U{--shiki-light:#267F99;--shiki-light-font-style:inherit;--shiki-default:#267F99;--shiki-default-font-style:inherit;--shiki-dark:#8BE9FD;--shiki-dark-font-style:italic}html pre.shiki code .s3JHE, html code.shiki .s3JHE{--shiki-light:#0070C1;--shiki-default:#0070C1;--shiki-dark:#F8F8F2}html pre.shiki code .s34zl, html code.shiki .s34zl{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#FF79C6}html pre.shiki code .sPzPf, html code.shiki .sPzPf{--shiki-light:#0070C1;--shiki-default:#0070C1;--shiki-dark:#BD93F9}",{"title":1012,"searchDepth":1216,"depth":1216,"links":2247},[2248,2252,2253,2254,2255,2256,2257,2258,2259],{"id":893,"depth":1216,"text":894,"children":2249},[2250,2251],{"id":905,"depth":1222,"text":906},{"id":998,"depth":1222,"text":999},{"id":1052,"depth":1216,"text":1053},{"id":1179,"depth":1216,"text":1180},{"id":1238,"depth":1216,"text":1239},{"id":1859,"depth":1216,"text":1860},{"id":1975,"depth":1216,"text":1976},{"id":2040,"depth":1216,"text":2041},{"id":2128,"depth":1216,"text":2129},{"id":2187,"depth":1216,"text":2188},"How the IAM service verifies inter-service requests using HMAC-SHA256 signatures, replay protection via a nonce cache, clock-skew tolerance, timing-safe comparison, and how to sign requests from calling services.","md",{},null,"---\ntitle: HMAC Authentication\ndescription: How the IAM service verifies inter-service requests using HMAC-SHA256 signatures, replay protection via a nonce cache, clock-skew tolerance, timing-safe comparison, and how to sign requests from calling services.\nicon: i-lucide-key-round\n---\n\nThe IAM service supports an optional [HMAC](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FHMAC) authentication layer for service-to-service communication. When enabled, every inbound request must carry four headers: a client identifier, a millisecond timestamp, a unique request ID, and an HMAC-SHA256 signature computed from a shared secret. The service verifies the signature using a constant-time comparison, rejects replayed requests via an [LRU](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCache_replacement_policies#Least_recently_used_(LRU)) nonce cache, and enforces a configurable clock-skew window.\n\nThis layer protects IAM endpoints from unauthorized access by services on the same private network. Without HMAC, any service that can reach the IAM port can call its API. With HMAC, only services that possess the shared secret can produce valid signatures.\n\n::note\nHMAC authentication is optional. Configure it in `service.Hmac` only when you have internal services that call IAM endpoints directly without going through the user-facing client. User-facing requests (browser to IAM) use cookie-based JWT authentication instead.\n::\n\n---\n\n## How it works\n\nThe `hmacAuth` middleware runs early in the Express middleware chain, before JSON body parsing and cookie parsing. It intercepts every inbound request and validates the four required headers before allowing the request to proceed.\n\n### Required headers\n\n| Header | Type | Description |\n|---|---|---|\n| `X-Client-Id` | `string` | The identifier of the calling service. Must match the `clientId` value in the IAM configuration. |\n| `X-Timestamp` | `string` | The client's current time in **milliseconds** since the Unix epoch. Used for clock-skew validation. |\n| `X-Request-ID` | `string` | A unique identifier for this specific request. Used for replay detection. Must never be reused. |\n| `X-Signature` | `string` | The hex-encoded HMAC-SHA256 signature of the request, computed from the shared secret. |\n\n### Signature computation\n\nThe signature is computed over a colon-separated string containing the client ID, timestamp, HTTP method, full request URL (including query string), and the request ID:\n\n```\nbase = \"{X-Client-Id}:{X-Timestamp}:{METHOD}:{originalUrl}:{X-Request-ID}\"\nsignature = HMAC-SHA256(sharedSecret, base).hex()\n```\n\nFor example, a POST request to `\u002Fauth\u002Fuser\u002Frefresh-session` from the `billing-service` client:\n\n```\nbase = \"billing-service:1712419200000:POST:\u002Fauth\u002Fuser\u002Frefresh-session:550e8400-e29b-41d4-a716-446655440000\"\nsignature = HMAC-SHA256(\"my-shared-secret\", base).hex()\n```\n\n::warning\nThe signature covers the `originalUrl`, not just the path. This means query parameters are included in the signed payload. A request to `\u002Fapi\u002Fusers?page=2` produces a different signature than `\u002Fapi\u002Fusers?page=3`. This prevents an attacker from modifying query parameters on a captured request.\n::\n\n---\n\n## Verification flow\n\nThe middleware performs five checks in sequence. The first failure short-circuits the chain and returns HTTP 401 with a reason string.\n\n::steps{level=\"4\"}\n#### Header presence\n\nAll four headers (`X-Client-Id`, `X-Timestamp`, `X-Signature`, `X-Request-ID`) must be present. If any is missing, the request is rejected with `'Missing auth headers'`.\n\n#### Client identity\n\nThe `X-Client-Id` value must exactly match `service.Hmac.clientId` from the configuration. If it does not match, the request is rejected with `'Unknown client'`.\n\n#### Clock-skew validation\n\nThe absolute difference between the server's current time (`Date.now()`) and the `X-Timestamp` value must be less than or equal to `maxClockSkew` milliseconds. If the timestamp is outside this window, the request is rejected with `'Stale timestamp'`.\n\nThis check serves two purposes: it prevents old captured requests from being replayed after the skew window expires, and it rejects requests with timestamps far in the future (which could indicate clock manipulation).\n\n#### Replay detection\n\nThe `X-Request-ID` is checked against an LRU nonce cache. If the ID already exists in the cache, the request is rejected with `'Replay detected'`. This catches an attacker replaying a valid request within the clock-skew window.\n\nThe nonce cache holds up to 5,000 entries with a TTL equal to `maxClockSkew`. Once the TTL expires, the nonce is evicted and a request with the same ID would pass the replay check, but it would then fail the clock-skew check because the original timestamp is now outside the window.\n\n#### Timing-safe signature comparison\n\nThe middleware recomputes the signature from the shared secret and the same base string format. It then compares the expected signature against the received `X-Signature` using `crypto.timingSafeEqual` on the hex-decoded buffers.\n\nBefore comparing, it verifies that both buffers are the same length. If the lengths differ, the request is rejected immediately (a length mismatch is always invalid). The constant-time comparison prevents [timing attacks](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FTiming_attack) that could leak information about the correct signature byte-by-byte.\n::\n\nOn success, the request ID is added to the nonce cache with a TTL of `maxClockSkew`, and the middleware calls `next()` to proceed to the route handler.\n\n---\n\n## Health check bypass\n\n`GET \u002Fhealth` requests from localhost (`127.0.0.1`, `::1`, or `::ffff:127.0.0.1`) bypass HMAC validation entirely. This allows container orchestrators (Docker, Kubernetes) to run health checks without needing access to the shared secret.\n\n```ts\n\u002F\u002F These requests skip HMAC validation:\n\u002F\u002F GET http:\u002F\u002F127.0.0.1:10000\u002Fhealth\n\u002F\u002F GET http:\u002F\u002F[::1]:10000\u002Fhealth\n```\n\n::warning\nOnly local health checks are exempt. A `GET \u002Fhealth` request from any non-local IP is subject to the full HMAC validation when the middleware is enabled.\n::\n\n---\n\n## Signing requests from a calling service\n\nThe calling service must compute the signature using the same base string format and the same shared secret. Here is a complete implementation:\n\n```ts\nimport crypto from 'node:crypto'\n\nfunction signRequest(\n  method: string,\n  url: string,\n  secret: string,\n  clientId: string\n): Record\u003Cstring, string> {\n  const timestamp = Date.now().toString()\n  const requestId = crypto.randomUUID()\n  const base = `${clientId}:${timestamp}:${method}:${url}:${requestId}`\n  const signature = crypto.createHmac('sha256', secret).update(base).digest('hex')\n\n  return {\n    'X-Client-Id': clientId,\n    'X-Timestamp': timestamp,\n    'X-Signature': signature,\n    'X-Request-ID': requestId,\n  }\n}\n\n\u002F\u002F Usage\nconst headers = signRequest(\n  'POST',\n  '\u002Fauth\u002Fuser\u002Frefresh-session',\n  process.env.HMAC_SECRET!,\n  'billing-service'\n)\n\nconst response = await fetch('https:\u002F\u002Fiam.internal\u002Fauth\u002Fuser\u002Frefresh-session', {\n  method: 'POST',\n  headers: {\n    ...headers,\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({ token: refreshToken }),\n})\n```\n\n::warning\nThe `X-Request-ID` must be globally unique per request. Use `crypto.randomUUID()` or a similar UUID generator. Reusing a request ID within the clock-skew window triggers the replay detection and the request is rejected.\n::\n\n---\n\n## Rejection handling\n\nWhen HMAC validation fails, the `reject` function sends an HTTP 401 response with the reason string as the body. It also logs the rejection with the client ID for audit purposes.\n\n| Reason | Cause |\n|---|---|\n| `Missing auth headers` | One or more required headers (`X-Client-Id`, `X-Timestamp`, `X-Signature`, `X-Request-ID`) are absent |\n| `Unknown client` | The `X-Client-Id` does not match the configured `clientId` |\n| `Stale timestamp` | The `X-Timestamp` is outside the `maxClockSkew` window |\n| `Replay detected` | The `X-Request-ID` was already used within the nonce cache TTL |\n| `Buffer Doesn't match` | The recomputed HMAC signature does not match `X-Signature` |\n\nEvery rejection is logged at `warn` level with `{ Authorized: false, reason, clientId }`. Successful validations are logged at `info` level with `{ Authorized: true, ClientID, Reason: 'Match' }`.\n\n---\n\n## Rotating the shared secret\n\nTo rotate the shared secret without downtime, update the services in the correct order:\n\n::steps{level=\"4\"}\n#### Update the IAM service\n\nSet the new `sharedSecret` in the IAM configuration and restart the service. The old secret is immediately invalid.\n\n#### Update calling services\n\nDeploy the updated `sharedSecret` to all calling services. Each service starts signing with the new secret immediately.\n\n#### Monitor for failures\n\nWatch the IAM logs for HMAC rejection entries (`reason: 'Buffer Doesn't match'`). These indicate a calling service is still using the old secret. Once no failures appear, the rotation is complete.\n::\n\n::tip\nUse a secrets manager ([AWS Secrets Manager](https:\u002F\u002Faws.amazon.com\u002Fsecrets-manager\u002F), [HashiCorp Vault](https:\u002F\u002Fwww.vaultproject.io\u002F), or environment variables injected by your orchestrator) to distribute the shared secret. Never hard-code it or commit it to version control.\n::\n\n::warning\nThere is no grace period or dual-key support during rotation. All calling services must be updated before or immediately after the IAM service restarts. Plan the rotation during a maintenance window or use a rolling deployment strategy where the IAM service is the last to restart.\n::\n\n---\n\n## Middleware mounting\n\nThe HMAC middleware is conditionally mounted in the Express application based on the `service.Hmac` configuration. When the `Hmac` block is not present (or `service` is undefined), the middleware is skipped entirely and all requests proceed without signature validation.\n\n```ts\n\u002F\u002F From the service bootstrap (simplified)\nif (config.service?.Hmac) {\n  app.use(hmacAuth)\n}\n```\n\nThe middleware is mounted **before** `express.json()` and `cookieParser()`, meaning it runs before the request body is parsed. This is intentional: if the signature is invalid, the service rejects the request without spending resources on body parsing.\n\n---\n\n## Configuration reference\n\nAll HMAC settings live under `service.Hmac` in the configuration.\n\n::field-group\n::field{name=\"service.Hmac.sharedSecret\" type=\"string\" required}\nThe shared secret key used to compute and verify HMAC-SHA256 signatures. Must be identical on the IAM service and all calling services. Use a cryptographically random string of at least 32 characters.\n::\n\n::field{name=\"service.Hmac.clientId\" type=\"string\" required}\nThe expected client identifier. Every request's `X-Client-Id` header must exactly match this value. Use a descriptive name for the calling service (e.g. `'billing-service'`, `'notification-worker'`).\n::\n\n::field{name=\"service.Hmac.maxClockSkew\" type=\"number\" default=\"300000\"}\nMaximum allowed difference in milliseconds between the server's current time and the request's `X-Timestamp`. Requests outside this window are rejected with `'Stale timestamp'`. The default is 300,000 ms (5 minutes). Lower values strengthen replay protection but require tighter clock synchronization between services.\n::\n::\n\n::tip\nIf your services run in containers with NTP synchronization, a `maxClockSkew` of 30,000 ms (30 seconds) is a reasonable starting point. Increase it only if you observe legitimate rejections due to clock drift.\n::\n\n---\n\n## Summary\n\n| System | Integration point |\n|---|---|\n| [Middleware chain](\u002Fdocs\u002Fiam\u002Fapi\u002Fmiddlewares) | HMAC runs before body parsing and cookie parsing, so invalid requests are rejected with minimal resource consumption |\n| [Rate limiting](\u002Fdocs\u002Fiam\u002Fessentials\u002Frate-limiting) | HMAC rejections do not consume rate limit tokens because the middleware rejects before reaching the rate limiter |\n| [Logging](\u002Fdocs\u002Fiam\u002Fessentials\u002Flogging) | Every HMAC validation (success or failure) is logged with the client ID, enabling audit trails for inter-service calls |\n| Health checks | `GET \u002Fhealth` from localhost bypasses HMAC, allowing container health probes without credentials |\n",{"title":135,"description":2260},"CrhpKkhbjb5gOY-2mtUQ9o73YvWbsvI2b50oB9gHoeQ",[2268,2269],{"title":131,"path":132,"stem":133,"children":-1},{"title":139,"path":140,"stem":141,"children":-1},{"id":851,"title":135,"body":2271,"description":2260,"extension":2261,"icon":21,"meta":3284,"module":2263,"navigation":8,"path":136,"rawbody":2264,"seo":3285,"stem":137,"__hash__":2266},{"type":853,"value":2272,"toc":3270},[2273,2281,2283,2289,2291,2293,2297,2299,2365,2367,2369,2374,2380,2385,2395,2397,2399,2401,2466,2472,2474,2476,2486,2502,2508,2510,2512,2514,2980,2988,2990,2992,2996,3068,3078,3080,3082,3084,3104,3114,3118,3120,3122,3130,3174,3182,3184,3186,3190,3214,3220,3222,3224,3268],[856,2274,858,2275,866,2278,872],{},[860,2276,865],{"href":862,"rel":2277},[864],[860,2279,871],{"href":869,"rel":2280},[864],[856,2282,875],{},[877,2284,2285],{},[856,2286,881,2287,886],{},[883,2288,885],{},[888,2290],{},[891,2292,894],{"id":893},[856,2294,897,2295,901],{},[883,2296,900],{},[903,2298,906],{"id":905},[908,2300,2301,2311],{},[911,2302,2303],{},[914,2304,2305,2307,2309],{},[917,2306,919],{},[917,2308,922],{},[917,2310,925],{},[927,2312,2313,2327,2341,2353],{},[914,2314,2315,2319,2323],{},[932,2316,2317],{},[883,2318,936],{},[932,2320,2321],{},[883,2322,941],{},[932,2324,944,2325,948],{},[883,2326,947],{},[914,2328,2329,2333,2337],{},[932,2330,2331],{},[883,2332,955],{},[932,2334,2335],{},[883,2336,941],{},[932,2338,962,2339,967],{},[964,2340,966],{},[914,2342,2343,2347,2351],{},[932,2344,2345],{},[883,2346,974],{},[932,2348,2349],{},[883,2350,941],{},[932,2352,981],{},[914,2354,2355,2359,2363],{},[932,2356,2357],{},[883,2358,988],{},[932,2360,2361],{},[883,2362,941],{},[932,2364,995],{},[903,2366,999],{"id":998},[856,2368,1002],{},[1004,2370,2372],{"className":2371,"code":1008,"language":1009},[1007],[883,2373,1008],{"__ignoreMap":1012},[856,2375,1015,2376,1019,2378,1023],{},[883,2377,1018],{},[883,2379,1022],{},[1004,2381,2383],{"className":2382,"code":1027,"language":1009},[1007],[883,2384,1027],{"__ignoreMap":1012},[1031,2386,2387],{},[856,2388,1035,2389,1039,2391,1043,2393,1047],{},[883,2390,1038],{},[883,2392,1042],{},[883,2394,1046],{},[888,2396],{},[891,2398,1053],{"id":1052},[856,2400,1056],{},[1058,2402,2403,2405,2417,2419,2427,2429,2439,2441,2443,2449,2453,2455,2461],{"level":1060},[1062,2404,1065],{"id":1064},[856,2406,1068,2407,1071,2409,1071,2411,1071,2413,1078,2415,1082],{},[883,2408,936],{},[883,2410,955],{},[883,2412,988],{},[883,2414,974],{},[883,2416,1081],{},[1062,2418,1086],{"id":1085},[856,2420,897,2421,1091,2423,1095,2425,1082],{},[883,2422,936],{},[883,2424,1094],{},[883,2426,1098],{},[1062,2428,1102],{"id":1101},[856,2430,1105,2431,1109,2433,1112,2435,1116,2437,1082],{},[883,2432,1108],{},[883,2434,955],{},[883,2436,1115],{},[883,2438,1119],{},[856,2440,1122],{},[1062,2442,1126],{"id":1125},[856,2444,897,2445,1131,2447,1135],{},[883,2446,974],{},[883,2448,1134],{},[856,2450,1138,2451,1141],{},[883,2452,1115],{},[1062,2454,1145],{"id":1144},[856,2456,1148,2457,1151,2459,1155],{},[883,2458,988],{},[883,2460,1154],{},[856,2462,1158,2463,1164],{},[860,2464,1163],{"href":1161,"rel":2465},[864],[856,2467,1167,2468,1170,2470,1174],{},[883,2469,1115],{},[883,2471,1173],{},[888,2473],{},[891,2475,1180],{"id":1179},[856,2477,2478,1186,2480,1071,2482,1193,2484,1197],{},[883,2479,1185],{},[883,2481,1189],{},[883,2483,1192],{},[883,2485,1196],{},[1004,2487,2488],{"className":1200,"code":1201,"language":1202,"meta":1012,"style":1012},[883,2489,2490,2494,2498],{"__ignoreMap":1012},[1206,2491,2492],{"class":1208,"line":1209},[1206,2493,1213],{"class":1212},[1206,2495,2496],{"class":1208,"line":1216},[1206,2497,1219],{"class":1212},[1206,2499,2500],{"class":1208,"line":1222},[1206,2501,1225],{"class":1212},[1031,2503,2504],{},[856,2505,1230,2506,1233],{},[883,2507,1185],{},[888,2509],{},[891,2511,1239],{"id":1238},[856,2513,1242],{},[1004,2515,2516],{"className":1200,"code":1245,"language":1202,"meta":1012,"style":1012},[883,2517,2518,2532,2536,2544,2554,2564,2574,2582,2600,2620,2636,2686,2734,2738,2744,2758,2772,2786,2800,2804,2808,2812,2816,2828,2838,2848,2864,2872,2876,2880,2902,2916,2924,2932,2950,2954,2976],{"__ignoreMap":1012},[1206,2519,2520,2522,2524,2526,2528,2530],{"class":1208,"line":1209},[1206,2521,1253],{"class":1252},[1206,2523,1257],{"class":1256},[1206,2525,1260],{"class":1252},[1206,2527,1264],{"class":1263},[1206,2529,1268],{"class":1267},[1206,2531,1271],{"class":1263},[1206,2533,2534],{"class":1208,"line":1216},[1206,2535,1276],{"emptyLinePlaceholder":8},[1206,2537,2538,2540,2542],{"class":1208,"line":1222},[1206,2539,1282],{"class":1281},[1206,2541,1286],{"class":1285},[1206,2543,1290],{"class":1289},[1206,2545,2546,2548,2550,2552],{"class":1208,"line":1293},[1206,2547,1297],{"class":1296},[1206,2549,1301],{"class":1300},[1206,2551,1305],{"class":1304},[1206,2553,1308],{"class":1289},[1206,2555,2556,2558,2560,2562],{"class":1208,"line":1311},[1206,2557,1314],{"class":1296},[1206,2559,1301],{"class":1300},[1206,2561,1305],{"class":1304},[1206,2563,1308],{"class":1289},[1206,2565,2566,2568,2570,2572],{"class":1208,"line":1323},[1206,2567,1326],{"class":1296},[1206,2569,1301],{"class":1300},[1206,2571,1305],{"class":1304},[1206,2573,1308],{"class":1289},[1206,2575,2576,2578,2580],{"class":1208,"line":1335},[1206,2577,1338],{"class":1296},[1206,2579,1301],{"class":1300},[1206,2581,1343],{"class":1304},[1206,2583,2584,2586,2588,2590,2592,2594,2596,2598],{"class":1208,"line":1346},[1206,2585,1349],{"class":1289},[1206,2587,1301],{"class":1300},[1206,2589,1354],{"class":1304},[1206,2591,1357],{"class":1289},[1206,2593,941],{"class":1304},[1206,2595,1071],{"class":1289},[1206,2597,941],{"class":1304},[1206,2599,1366],{"class":1289},[1206,2601,2602,2604,2606,2608,2610,2612,2614,2616,2618],{"class":1208,"line":1369},[1206,2603,1372],{"class":1281},[1206,2605,1376],{"class":1375},[1206,2607,1379],{"class":1300},[1206,2609,1382],{"class":1256},[1206,2611,1082],{"class":1289},[1206,2613,1387],{"class":1285},[1206,2615,1390],{"class":1289},[1206,2617,1393],{"class":1285},[1206,2619,1396],{"class":1289},[1206,2621,2622,2624,2626,2628,2630,2632,2634],{"class":1208,"line":1399},[1206,2623,1372],{"class":1281},[1206,2625,1404],{"class":1375},[1206,2627,1379],{"class":1300},[1206,2629,1257],{"class":1256},[1206,2631,1082],{"class":1289},[1206,2633,1413],{"class":1285},[1206,2635,1396],{"class":1289},[1206,2637,2638,2640,2642,2644,2646,2648,2650,2652,2654,2656,2658,2660,2662,2664,2666,2668,2670,2672,2674,2676,2678,2680,2682,2684],{"class":1208,"line":1418},[1206,2639,1372],{"class":1281},[1206,2641,1423],{"class":1375},[1206,2643,1379],{"class":1300},[1206,2645,1428],{"class":1267},[1206,2647,1431],{"class":1281},[1206,2649,947],{"class":1256},[1206,2651,1436],{"class":1281},[1206,2653,1301],{"class":1267},[1206,2655,1431],{"class":1281},[1206,2657,1443],{"class":1256},[1206,2659,1436],{"class":1281},[1206,2661,1301],{"class":1267},[1206,2663,1431],{"class":1281},[1206,2665,1452],{"class":1256},[1206,2667,1436],{"class":1281},[1206,2669,1301],{"class":1267},[1206,2671,1431],{"class":1281},[1206,2673,1461],{"class":1256},[1206,2675,1436],{"class":1281},[1206,2677,1301],{"class":1267},[1206,2679,1431],{"class":1281},[1206,2681,1470],{"class":1256},[1206,2683,1436],{"class":1281},[1206,2685,1475],{"class":1267},[1206,2687,2688,2690,2692,2694,2696,2698,2700,2702,2704,2706,2708,2710,2712,2714,2716,2718,2720,2722,2724,2726,2728,2730,2732],{"class":1208,"line":1478},[1206,2689,1372],{"class":1281},[1206,2691,1483],{"class":1375},[1206,2693,1379],{"class":1300},[1206,2695,1257],{"class":1256},[1206,2697,1082],{"class":1289},[1206,2699,1492],{"class":1285},[1206,2701,1495],{"class":1289},[1206,2703,1498],{"class":1263},[1206,2705,1501],{"class":1267},[1206,2707,1498],{"class":1263},[1206,2709,1071],{"class":1289},[1206,2711,1508],{"class":1256},[1206,2713,1511],{"class":1289},[1206,2715,1514],{"class":1285},[1206,2717,1495],{"class":1289},[1206,2719,1519],{"class":1256},[1206,2721,1511],{"class":1289},[1206,2723,1524],{"class":1285},[1206,2725,1495],{"class":1289},[1206,2727,1498],{"class":1263},[1206,2729,1531],{"class":1267},[1206,2731,1498],{"class":1263},[1206,2733,1536],{"class":1289},[1206,2735,2736],{"class":1208,"line":1539},[1206,2737,1276],{"emptyLinePlaceholder":8},[1206,2739,2740,2742],{"class":1208,"line":1544},[1206,2741,1547],{"class":1252},[1206,2743,1550],{"class":1289},[1206,2745,2746,2748,2750,2752,2754,2756],{"class":1208,"line":1553},[1206,2747,1556],{"class":1263},[1206,2749,936],{"class":1267},[1206,2751,1498],{"class":1263},[1206,2753,1301],{"class":1563},[1206,2755,1566],{"class":1256},[1206,2757,1308],{"class":1289},[1206,2759,2760,2762,2764,2766,2768,2770],{"class":1208,"line":1571},[1206,2761,1556],{"class":1263},[1206,2763,955],{"class":1267},[1206,2765,1498],{"class":1263},[1206,2767,1301],{"class":1563},[1206,2769,1376],{"class":1256},[1206,2771,1308],{"class":1289},[1206,2773,2774,2776,2778,2780,2782,2784],{"class":1208,"line":1586},[1206,2775,1556],{"class":1263},[1206,2777,988],{"class":1267},[1206,2779,1498],{"class":1263},[1206,2781,1301],{"class":1563},[1206,2783,1483],{"class":1256},[1206,2785,1308],{"class":1289},[1206,2787,2788,2790,2792,2794,2796,2798],{"class":1208,"line":1601},[1206,2789,1556],{"class":1263},[1206,2791,974],{"class":1267},[1206,2793,1498],{"class":1263},[1206,2795,1301],{"class":1563},[1206,2797,1404],{"class":1256},[1206,2799,1308],{"class":1289},[1206,2801,2802],{"class":1208,"line":1616},[1206,2803,1619],{"class":1289},[1206,2805,2806],{"class":1208,"line":1622},[1206,2807,1625],{"class":1289},[1206,2809,2810],{"class":1208,"line":1628},[1206,2811,1276],{"emptyLinePlaceholder":8},[1206,2813,2814],{"class":1208,"line":1633},[1206,2815,1636],{"class":1212},[1206,2817,2818,2820,2822,2824,2826],{"class":1208,"line":1639},[1206,2819,1642],{"class":1281},[1206,2821,1645],{"class":1375},[1206,2823,1379],{"class":1300},[1206,2825,1286],{"class":1285},[1206,2827,1290],{"class":1289},[1206,2829,2830,2832,2834,2836],{"class":1208,"line":1654},[1206,2831,1657],{"class":1263},[1206,2833,1660],{"class":1267},[1206,2835,1498],{"class":1263},[1206,2837,1308],{"class":1289},[1206,2839,2840,2842,2844,2846],{"class":1208,"line":1667},[1206,2841,1657],{"class":1263},[1206,2843,1018],{"class":1267},[1206,2845,1498],{"class":1263},[1206,2847,1308],{"class":1289},[1206,2849,2850,2852,2854,2856,2858,2860,2862],{"class":1208,"line":1678},[1206,2851,1681],{"class":1256},[1206,2853,1082],{"class":1289},[1206,2855,1686],{"class":1256},[1206,2857,1082],{"class":1289},[1206,2859,1692],{"class":1691},[1206,2861,1695],{"class":1300},[1206,2863,1308],{"class":1289},[1206,2865,2866,2868,2870],{"class":1208,"line":1700},[1206,2867,1657],{"class":1263},[1206,2869,1022],{"class":1267},[1206,2871,1271],{"class":1263},[1206,2873,2874],{"class":1208,"line":1709},[1206,2875,1536],{"class":1289},[1206,2877,2878],{"class":1208,"line":1714},[1206,2879,1276],{"emptyLinePlaceholder":8},[1206,2881,2882,2884,2886,2888,2890,2892,2894,2896,2898,2900],{"class":1208,"line":1719},[1206,2883,1642],{"class":1281},[1206,2885,1724],{"class":1375},[1206,2887,1379],{"class":1300},[1206,2889,1729],{"class":1252},[1206,2891,1732],{"class":1285},[1206,2893,1495],{"class":1289},[1206,2895,1498],{"class":1263},[1206,2897,1739],{"class":1267},[1206,2899,1498],{"class":1263},[1206,2901,1744],{"class":1289},[1206,2903,2904,2906,2908,2910,2912,2914],{"class":1208,"line":1747},[1206,2905,1297],{"class":1256},[1206,2907,1301],{"class":1563},[1206,2909,1264],{"class":1263},[1206,2911,1660],{"class":1267},[1206,2913,1498],{"class":1263},[1206,2915,1308],{"class":1289},[1206,2917,2918,2920,2922],{"class":1208,"line":1762},[1206,2919,1765],{"class":1256},[1206,2921,1301],{"class":1563},[1206,2923,1550],{"class":1289},[1206,2925,2926,2928,2930],{"class":1208,"line":1772},[1206,2927,1775],{"class":1300},[1206,2929,1778],{"class":1256},[1206,2931,1308],{"class":1289},[1206,2933,2934,2936,2938,2940,2942,2944,2946,2948],{"class":1208,"line":1783},[1206,2935,1556],{"class":1263},[1206,2937,1788],{"class":1267},[1206,2939,1498],{"class":1263},[1206,2941,1301],{"class":1563},[1206,2943,1264],{"class":1263},[1206,2945,1797],{"class":1267},[1206,2947,1498],{"class":1263},[1206,2949,1308],{"class":1289},[1206,2951,2952],{"class":1208,"line":1804},[1206,2953,1807],{"class":1289},[1206,2955,2956,2958,2960,2962,2964,2966,2968,2970,2972,2974],{"class":1208,"line":1810},[1206,2957,1813],{"class":1256},[1206,2959,1301],{"class":1563},[1206,2961,1818],{"class":1691},[1206,2963,1082],{"class":1289},[1206,2965,1823],{"class":1285},[1206,2967,1826],{"class":1289},[1206,2969,1829],{"class":1256},[1206,2971,1301],{"class":1563},[1206,2973,1834],{"class":1256},[1206,2975,1837],{"class":1289},[1206,2977,2978],{"class":1208,"line":1840},[1206,2979,1843],{"class":1289},[1031,2981,2982],{},[856,2983,897,2984,1850,2986,1854],{},[883,2985,974],{},[883,2987,1853],{},[888,2989],{},[891,2991,1860],{"id":1859},[856,2993,1863,2994,1867],{},[883,2995,1866],{},[908,2997,2998,3006],{},[911,2999,3000],{},[914,3001,3002,3004],{},[917,3003,1876],{},[917,3005,1879],{},[927,3007,3008,3024,3036,3048,3058],{},[914,3009,3010,3014],{},[932,3011,3012],{},[883,3013,1888],{},[932,3015,1891,3016,1071,3018,1071,3020,1071,3022,1900],{},[883,3017,936],{},[883,3019,955],{},[883,3021,988],{},[883,3023,974],{},[914,3025,3026,3030],{},[932,3027,3028],{},[883,3029,1907],{},[932,3031,897,3032,1912,3034],{},[883,3033,936],{},[883,3035,947],{},[914,3037,3038,3042],{},[932,3039,3040],{},[883,3041,1921],{},[932,3043,897,3044,1926,3046,1929],{},[883,3045,955],{},[883,3047,1115],{},[914,3049,3050,3054],{},[932,3051,3052],{},[883,3053,1936],{},[932,3055,897,3056,1941],{},[883,3057,974],{},[914,3059,3060,3064],{},[932,3061,3062],{},[883,3063,1948],{},[932,3065,1951,3066],{},[883,3067,988],{},[856,3069,1956,3070,1960,3072,1964,3074,1960,3076,1082],{},[883,3071,1959],{},[883,3073,1963],{},[883,3075,1967],{},[883,3077,1970],{},[888,3079],{},[891,3081,1976],{"id":1975},[856,3083,1979],{},[1058,3085,3086,3088,3092,3094,3098,3100],{"level":1060},[1062,3087,1985],{"id":1984},[856,3089,1988,3090,1992],{},[883,3091,1991],{},[1062,3093,1996],{"id":1995},[856,3095,1999,3096,2002],{},[883,3097,1991],{},[1062,3099,2006],{"id":2005},[856,3101,2009,3102,2013],{},[883,3103,2012],{},[2015,3105,3106],{},[856,3107,2019,3108,1071,3111,2030],{},[860,3109,2024],{"href":2022,"rel":3110},[864],[860,3112,2029],{"href":2027,"rel":3113},[864],[1031,3115,3116],{},[856,3117,2035],{},[888,3119],{},[891,3121,2041],{"id":2040},[856,3123,2044,3124,2047,3126,2051,3128,2055],{},[883,3125,885],{},[883,3127,2050],{},[883,3129,2054],{},[1004,3131,3132],{"className":1200,"code":2058,"language":1202,"meta":1012,"style":1012},[883,3133,3134,3138,3156,3170],{"__ignoreMap":1012},[1206,3135,3136],{"class":1208,"line":1209},[1206,3137,2065],{"class":1212},[1206,3139,3140,3142,3144,3146,3148,3150,3152,3154],{"class":1208,"line":1216},[1206,3141,2070],{"class":1252},[1206,3143,2073],{"class":1289},[1206,3145,2076],{"class":1256},[1206,3147,1082],{"class":1289},[1206,3149,2054],{"class":1256},[1206,3151,2083],{"class":1289},[1206,3153,2050],{"class":1256},[1206,3155,2088],{"class":1289},[1206,3157,3158,3160,3162,3164,3166,3168],{"class":1208,"line":1222},[1206,3159,2093],{"class":1256},[1206,3161,1082],{"class":1289},[1206,3163,2098],{"class":1285},[1206,3165,1495],{"class":1289},[1206,3167,900],{"class":1256},[1206,3169,1536],{"class":1289},[1206,3171,3172],{"class":1208,"line":1293},[1206,3173,1625],{"class":1289},[856,3175,2111,3176,2115,3178,2119,3180,2123],{},[964,3177,2114],{},[883,3179,2118],{},[883,3181,2122],{},[888,3183],{},[891,3185,2129],{"id":2128},[856,3187,2132,3188,2135],{},[883,3189,885],{},[2137,3191,3192,3196,3206],{},[2140,3193,3194],{"name":2142,"type":941,":required":2143},[856,3195,2146],{},[2140,3197,3198],{"name":1094,"type":941,":required":2143},[856,3199,2151,3200,2154,3202,1071,3204,1511],{},[883,3201,936],{},[883,3203,2157],{},[883,3205,2160],{},[2140,3207,3208],{"name":2163,"type":2164,"default":2165},[856,3209,2168,3210,2171,3212,2174],{},[883,3211,955],{},[883,3213,1119],{},[2015,3215,3216],{},[856,3217,2179,3218,2182],{},[883,3219,1115],{},[888,3221],{},[891,3223,2188],{"id":2187},[908,3225,3226,3234],{},[911,3227,3228],{},[914,3229,3230,3232],{},[917,3231,2197],{},[917,3233,2200],{},[927,3235,3236,3244,3252,3260],{},[914,3237,3238,3242],{},[932,3239,3240],{},[860,3241,2209],{"href":251},[932,3243,2212],{},[914,3245,3246,3250],{},[932,3247,3248],{},[860,3249,2219],{"href":148},[932,3251,2222],{},[914,3253,3254,3258],{},[932,3255,3256],{},[860,3257,143],{"href":144},[932,3259,2231],{},[914,3261,3262,3264],{},[932,3263,2236],{},[932,3265,3266,2241],{},[883,3267,1185],{},[2243,3269,2245],{},{"title":1012,"searchDepth":1216,"depth":1216,"links":3271},[3272,3276,3277,3278,3279,3280,3281,3282,3283],{"id":893,"depth":1216,"text":894,"children":3273},[3274,3275],{"id":905,"depth":1222,"text":906},{"id":998,"depth":1222,"text":999},{"id":1052,"depth":1216,"text":1053},{"id":1179,"depth":1216,"text":1180},{"id":1238,"depth":1216,"text":1239},{"id":1859,"depth":1216,"text":1860},{"id":1975,"depth":1216,"text":1976},{"id":2040,"depth":1216,"text":2041},{"id":2128,"depth":1216,"text":2129},{"id":2187,"depth":1216,"text":2188},{},{"title":135,"description":2260},1780436282468]