[{"data":1,"prerenderedAt":3755},["ShallowReactive",2],{"navLinks":3,"sidebar_docs_navigation_\u002Fdocs\u002Fiam":64,"navigation":257,"navLinks_footer":837,"\u002Fdocs\u002Fiam\u002Fessentials\u002Ftokens_page":850,"\u002Fdocs\u002Fiam\u002Fessentials\u002Ftokens_surround":2463,"\u002Fdocs\u002Fiam\u002Fessentials\u002Ftokens":2466},{"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":83,"body":852,"description":2456,"extension":2457,"icon":21,"meta":2458,"module":2459,"navigation":8,"path":84,"rawbody":2460,"seo":2461,"stem":85,"__hash__":2462},"docs\u002Fdocs\u002Fiam\u002F01.essentials\u002F00.tokens.md",{"type":853,"value":854,"toc":2440},"minimark",[855,877,888,901,904,908,919,924,931,1096,1099,1115,1119,1122,1222,1287,1291,1318,1452,1459,1462,1608,1612,1619,1678,1681,1687,1689,1692,1698,1702,1818,1821,1831,1835,1842,1942,1953,1957,1965,2040,2043,2047,2054,2105,2107,2111,2118,2133,2150,2153,2171,2174,2246,2249,2371,2375,2384,2390,2396,2416,2422,2425,2436],[856,857,858,859,863,864,868,869,872,873,876],"p",{},"The IAM service uses a two token architecture and a ",[860,861,862],"code",{},"canary_id"," cookie for anomalies detection. A short-lived ",[865,866,867],"strong",{},"access token"," and A long-lived ",[865,870,871],{},"refresh token",".\nThe access token is sent as a json field to clients, while clients needs to send it back in a ",[860,874,875],{},"Authorization: Bearer \u003Ctoken>"," header for verification.",[856,878,879,880,883,884,887],{},"Refresh tokens are long-lived, stored hashed with ",[860,881,882],{},"sha-256"," in MySQL and sent via an ",[860,885,886],{},"httpOnly"," cookie to clients. Clients needs to send this cookie back for verification.",[856,889,890,891,893,894,900],{},"The ",[860,892,862],{}," cookie, is generated by the ",[895,896,897],"a",{"href":35},[860,898,899],{},"bot-detector",", and should be included by clients on any sensitive request. This cookie is tied to the token family, and invalid cookie will be flagged.",[902,903],"hr",{},[905,906,87],"h2",{"id":907},"access-tokens",[856,909,910,911,914,915,918],{},"Access tokens are signed JWTs. The service signs them with the ",[860,912,913],{},"jwt.jwt_secret_key"," configured in ",[860,916,917],{},"configuration()"," and caches verified tokens in an LRU cache for the duration of their validity.",[920,921,923],"h3",{"id":922},"generating-an-access-token","Generating an access token",[856,925,926,927,930],{},"When using the service as a library, you can generate an access token with ",[860,928,929],{},"generateAccessToken",":",[932,933,938],"pre",{"className":934,"code":935,"language":936,"meta":937,"style":937},"language-ts shiki shiki-themes light-plus light-plus dracula","import { generateAccessToken } from '@riavzon\u002Fauth'\n\nconst token = generateAccessToken({\n  id: user.id,\n  visitor_id: user.visitor_id,\n  jti: crypto.randomUUID(),\n  roles: [\"user\", \"admin\"]\n})\n\n","ts","",[860,939,940,973,979,1001,1022,1039,1058,1090],{"__ignoreMap":937},[941,942,945,949,953,956,959,962,966,970],"span",{"class":943,"line":944},"line",1,[941,946,948],{"class":947},"sZ328","import",[941,950,952],{"class":951},"sDd4n"," { ",[941,954,929],{"class":955},"sjsA6",[941,957,958],{"class":951}," } ",[941,960,961],{"class":947},"from",[941,963,965],{"class":964},"sFkSl"," '",[941,967,969],{"class":968},"sFB1V","@riavzon\u002Fauth",[941,971,972],{"class":964},"'\n",[941,974,976],{"class":943,"line":975},2,[941,977,978],{"emptyLinePlaceholder":8},"\n",[941,980,982,986,990,994,998],{"class":943,"line":981},3,[941,983,985],{"class":984},"sl46w","const",[941,987,989],{"class":988},"s3JHE"," token",[941,991,993],{"class":992},"saOXh"," =",[941,995,997],{"class":996},"sHOzp"," generateAccessToken",[941,999,1000],{"class":951},"({\n",[941,1002,1004,1007,1010,1013,1016,1019],{"class":943,"line":1003},4,[941,1005,1006],{"class":955},"  id",[941,1008,930],{"class":1009},"s34zl",[941,1011,1012],{"class":955}," user",[941,1014,1015],{"class":951},".",[941,1017,1018],{"class":955},"id",[941,1020,1021],{"class":951},",\n",[941,1023,1025,1028,1030,1032,1034,1037],{"class":943,"line":1024},5,[941,1026,1027],{"class":955},"  visitor_id",[941,1029,930],{"class":1009},[941,1031,1012],{"class":955},[941,1033,1015],{"class":951},[941,1035,1036],{"class":955},"visitor_id",[941,1038,1021],{"class":951},[941,1040,1042,1045,1047,1050,1052,1055],{"class":943,"line":1041},6,[941,1043,1044],{"class":955},"  jti",[941,1046,930],{"class":1009},[941,1048,1049],{"class":955}," crypto",[941,1051,1015],{"class":951},[941,1053,1054],{"class":996},"randomUUID",[941,1056,1057],{"class":951},"(),\n",[941,1059,1061,1064,1066,1069,1072,1075,1077,1080,1082,1085,1087],{"class":943,"line":1060},7,[941,1062,1063],{"class":955},"  roles",[941,1065,930],{"class":1009},[941,1067,1068],{"class":951}," [",[941,1070,1071],{"class":964},"\"",[941,1073,1074],{"class":968},"user",[941,1076,1071],{"class":964},[941,1078,1079],{"class":951},", ",[941,1081,1071],{"class":964},[941,1083,1084],{"class":968},"admin",[941,1086,1071],{"class":964},[941,1088,1089],{"class":951},"]\n",[941,1091,1093],{"class":943,"line":1092},8,[941,1094,1095],{"class":951},"})\n",[856,1097,1098],{},"When using the standalone service, access tokens are sent to clients when they:",[1100,1101,1102,1106,1109,1112],"ul",{},[1103,1104,1105],"li",{},"Make an account",[1103,1107,1108],{},"Login to their account",[1103,1110,1111],{},"Try to rotate their session",[1103,1113,1114],{},"Proof their identity via an MFA flow.",[920,1116,1118],{"id":1117},"verifying-an-access-token","Verifying an access token",[856,1120,1121],{},"When using the service as a library:",[932,1123,1125],{"className":934,"code":1124,"language":936,"meta":937,"style":937},"import { verifyAccessToken } from '@riavzon\u002Fauth'\n\nconst { valid, payload, errorType } = verifyAccessToken(token)\n\nif (!valid) {\n  \u002F\u002F errorType is 'TokenExpiredError' for expired tokens\n  \u002F\u002F or a description string for other failures\n}\n",[860,1126,1127,1146,1150,1186,1190,1206,1212,1217],{"__ignoreMap":937},[941,1128,1129,1131,1133,1136,1138,1140,1142,1144],{"class":943,"line":944},[941,1130,948],{"class":947},[941,1132,952],{"class":951},[941,1134,1135],{"class":955},"verifyAccessToken",[941,1137,958],{"class":951},[941,1139,961],{"class":947},[941,1141,965],{"class":964},[941,1143,969],{"class":968},[941,1145,972],{"class":964},[941,1147,1148],{"class":943,"line":975},[941,1149,978],{"emptyLinePlaceholder":8},[941,1151,1152,1154,1156,1159,1161,1164,1166,1169,1171,1174,1177,1180,1183],{"class":943,"line":981},[941,1153,985],{"class":984},[941,1155,952],{"class":951},[941,1157,1158],{"class":988},"valid",[941,1160,1079],{"class":951},[941,1162,1163],{"class":988},"payload",[941,1165,1079],{"class":951},[941,1167,1168],{"class":988},"errorType",[941,1170,958],{"class":951},[941,1172,1173],{"class":992},"=",[941,1175,1176],{"class":996}," verifyAccessToken",[941,1178,1179],{"class":951},"(",[941,1181,1182],{"class":955},"token",[941,1184,1185],{"class":951},")\n",[941,1187,1188],{"class":943,"line":1003},[941,1189,978],{"emptyLinePlaceholder":8},[941,1191,1192,1195,1198,1201,1203],{"class":943,"line":1024},[941,1193,1194],{"class":947},"if",[941,1196,1197],{"class":951}," (",[941,1199,1200],{"class":992},"!",[941,1202,1158],{"class":955},[941,1204,1205],{"class":951},") {\n",[941,1207,1208],{"class":943,"line":1041},[941,1209,1211],{"class":1210},"sghk6","  \u002F\u002F errorType is 'TokenExpiredError' for expired tokens\n",[941,1213,1214],{"class":943,"line":1060},[941,1215,1216],{"class":1210},"  \u002F\u002F or a description string for other failures\n",[941,1218,1219],{"class":943,"line":1092},[941,1220,1221],{"class":951},"}\n",[1223,1224,1225,1241],"table",{},[1226,1227,1228],"thead",{},[1229,1230,1231,1235,1238],"tr",{},[1232,1233,1234],"th",{},"Field",[1232,1236,1237],{},"Type",[1232,1239,1240],{},"Description",[1242,1243,1244,1259,1273],"tbody",{},[1229,1245,1246,1251,1256],{},[1247,1248,1249],"td",{},[860,1250,1158],{},[1247,1252,1253],{},[860,1254,1255],{},"boolean",[1247,1257,1258],{},"Whether the token passed signature and expiry checks",[1229,1260,1261,1265,1270],{},[1247,1262,1263],{},[860,1264,1163],{},[1247,1266,1267],{},[860,1268,1269],{},"JwtPayload | undefined",[1247,1271,1272],{},"Decoded claims when valid",[1229,1274,1275,1279,1284],{},[1247,1276,1277],{},[860,1278,1168],{},[1247,1280,1281],{},[860,1282,1283],{},"string | undefined",[1247,1285,1286],{},"Error description when invalid",[920,1288,1290],{"id":1289},"token-payload","Token payload",[856,1292,1293,1294,1079,1297,1079,1300,1079,1303,1079,1306,1309,1310,1313,1314,1317],{},"The default payload includes ",[860,1295,1296],{},"visitor",[860,1298,1299],{},"roles",[860,1301,1302],{},"sub",[860,1304,1305],{},"jti",[860,1307,1308],{},"iat",", and ",[860,1311,1312],{},"exp",". Additional claims are merged from ",[860,1315,1316],{},"jwt.access_tokens.payload"," in the configuration.",[932,1319,1322],{"className":1320,"code":1321,"language":5,"meta":937,"style":937},"language-json shiki shiki-themes light-plus light-plus dracula","{\n  \"visitor\": \"vis_abc123\",\n  \"roles\": [\"user\", \"admin\"],\n  \"sub\": \"42\",\n  \"jti\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"iat\": 1710000000,\n  \"exp\": 1710000900\n}\n",[860,1323,1324,1329,1352,1381,1400,1419,1435,1448],{"__ignoreMap":937},[941,1325,1326],{"class":943,"line":944},[941,1327,1328],{"class":951},"{\n",[941,1330,1331,1335,1338,1340,1342,1345,1348,1350],{"class":943,"line":975},[941,1332,1334],{"class":1333},"saJyd","  \"",[941,1336,1296],{"class":1337},"s_W10",[941,1339,1071],{"class":1333},[941,1341,930],{"class":992},[941,1343,1344],{"class":964}," \"",[941,1346,1347],{"class":968},"vis_abc123",[941,1349,1071],{"class":964},[941,1351,1021],{"class":951},[941,1353,1354,1356,1358,1360,1362,1364,1366,1368,1370,1372,1374,1376,1378],{"class":943,"line":981},[941,1355,1334],{"class":1333},[941,1357,1299],{"class":1337},[941,1359,1071],{"class":1333},[941,1361,930],{"class":992},[941,1363,1068],{"class":951},[941,1365,1071],{"class":964},[941,1367,1074],{"class":968},[941,1369,1071],{"class":964},[941,1371,1079],{"class":951},[941,1373,1071],{"class":964},[941,1375,1084],{"class":968},[941,1377,1071],{"class":964},[941,1379,1380],{"class":951},"],\n",[941,1382,1383,1385,1387,1389,1391,1393,1396,1398],{"class":943,"line":1003},[941,1384,1334],{"class":1333},[941,1386,1302],{"class":1337},[941,1388,1071],{"class":1333},[941,1390,930],{"class":992},[941,1392,1344],{"class":964},[941,1394,1395],{"class":968},"42",[941,1397,1071],{"class":964},[941,1399,1021],{"class":951},[941,1401,1402,1404,1406,1408,1410,1412,1415,1417],{"class":943,"line":1024},[941,1403,1334],{"class":1333},[941,1405,1305],{"class":1337},[941,1407,1071],{"class":1333},[941,1409,930],{"class":992},[941,1411,1344],{"class":964},[941,1413,1414],{"class":968},"550e8400-e29b-41d4-a716-446655440000",[941,1416,1071],{"class":964},[941,1418,1021],{"class":951},[941,1420,1421,1423,1425,1427,1429,1433],{"class":943,"line":1041},[941,1422,1334],{"class":1333},[941,1424,1308],{"class":1337},[941,1426,1071],{"class":1333},[941,1428,930],{"class":992},[941,1430,1432],{"class":1431},"spgvN"," 1710000000",[941,1434,1021],{"class":951},[941,1436,1437,1439,1441,1443,1445],{"class":943,"line":1060},[941,1438,1334],{"class":1333},[941,1440,1312],{"class":1337},[941,1442,1071],{"class":1333},[941,1444,930],{"class":992},[941,1446,1447],{"class":1431}," 1710000900\n",[941,1449,1450],{"class":943,"line":1092},[941,1451,1221],{"class":951},[856,1453,1454,1455,1458],{},"When using the service directly, you should send access tokens to the ",[860,1456,1457],{},"\u002Fsecret\u002Fdata"," route.\nThis route requires the access token header, canary_id cookie, and the refresh token cookie.",[856,1460,1461],{},"When verification passes, you get back a json data with the following fields:",[932,1463,1465],{"className":1320,"code":1464,"language":5,"meta":937,"style":937}," {\n    \"userId\": 1234,\n    \"authorized\": true,\n    \"ipAddress\": \"1.1.1.1\",\n    \"userAgent\":  \"client user agent\",\n    \"date\": \"iso formatted date\",\n    \"roles\": [\"admin\", \"user\", \"etc\"]\n  }\n",[860,1466,1467,1472,1489,1506,1526,1546,1566,1603],{"__ignoreMap":937},[941,1468,1469],{"class":943,"line":944},[941,1470,1471],{"class":951}," {\n",[941,1473,1474,1477,1480,1482,1484,1487],{"class":943,"line":975},[941,1475,1476],{"class":1333},"    \"",[941,1478,1479],{"class":1337},"userId",[941,1481,1071],{"class":1333},[941,1483,930],{"class":992},[941,1485,1486],{"class":1431}," 1234",[941,1488,1021],{"class":951},[941,1490,1491,1493,1496,1498,1500,1504],{"class":943,"line":981},[941,1492,1476],{"class":1333},[941,1494,1495],{"class":1337},"authorized",[941,1497,1071],{"class":1333},[941,1499,930],{"class":992},[941,1501,1503],{"class":1502},"sjR7W"," true",[941,1505,1021],{"class":951},[941,1507,1508,1510,1513,1515,1517,1519,1522,1524],{"class":943,"line":1003},[941,1509,1476],{"class":1333},[941,1511,1512],{"class":1337},"ipAddress",[941,1514,1071],{"class":1333},[941,1516,930],{"class":992},[941,1518,1344],{"class":964},[941,1520,1521],{"class":968},"1.1.1.1",[941,1523,1071],{"class":964},[941,1525,1021],{"class":951},[941,1527,1528,1530,1533,1535,1537,1539,1542,1544],{"class":943,"line":1024},[941,1529,1476],{"class":1333},[941,1531,1532],{"class":1337},"userAgent",[941,1534,1071],{"class":1333},[941,1536,930],{"class":992},[941,1538,1334],{"class":964},[941,1540,1541],{"class":968},"client user agent",[941,1543,1071],{"class":964},[941,1545,1021],{"class":951},[941,1547,1548,1550,1553,1555,1557,1559,1562,1564],{"class":943,"line":1041},[941,1549,1476],{"class":1333},[941,1551,1552],{"class":1337},"date",[941,1554,1071],{"class":1333},[941,1556,930],{"class":992},[941,1558,1344],{"class":964},[941,1560,1561],{"class":968},"iso formatted date",[941,1563,1071],{"class":964},[941,1565,1021],{"class":951},[941,1567,1568,1570,1572,1574,1576,1578,1580,1582,1584,1586,1588,1590,1592,1594,1596,1599,1601],{"class":943,"line":1060},[941,1569,1476],{"class":1333},[941,1571,1299],{"class":1337},[941,1573,1071],{"class":1333},[941,1575,930],{"class":992},[941,1577,1068],{"class":951},[941,1579,1071],{"class":964},[941,1581,1084],{"class":968},[941,1583,1071],{"class":964},[941,1585,1079],{"class":951},[941,1587,1071],{"class":964},[941,1589,1074],{"class":968},[941,1591,1071],{"class":964},[941,1593,1079],{"class":951},[941,1595,1071],{"class":964},[941,1597,1598],{"class":968},"etc",[941,1600,1071],{"class":964},[941,1602,1089],{"class":951},[941,1604,1605],{"class":943,"line":1092},[941,1606,1607],{"class":951},"  }\n",[920,1609,1611],{"id":1610},"cache","Cache",[856,1613,1614,1615,1618],{},"The access token cache is an LRU cache keyed by the signed token string. Its size is controlled by ",[860,1616,1617],{},"jwt.access_tokens.maxCacheEntries",". Import the cache directly if you need to inspect or clear it:",[932,1620,1622],{"className":934,"code":1621,"language":936,"meta":937,"style":937},"import { tokenCache } from '@riavzon\u002Fauth'\n\nconst cache = tokenCache()\ncache.delete(rawToken)\n\n",[860,1623,1624,1643,1647,1662],{"__ignoreMap":937},[941,1625,1626,1628,1630,1633,1635,1637,1639,1641],{"class":943,"line":944},[941,1627,948],{"class":947},[941,1629,952],{"class":951},[941,1631,1632],{"class":955},"tokenCache",[941,1634,958],{"class":951},[941,1636,961],{"class":947},[941,1638,965],{"class":964},[941,1640,969],{"class":968},[941,1642,972],{"class":964},[941,1644,1645],{"class":943,"line":975},[941,1646,978],{"emptyLinePlaceholder":8},[941,1648,1649,1651,1654,1656,1659],{"class":943,"line":981},[941,1650,985],{"class":984},[941,1652,1653],{"class":988}," cache",[941,1655,993],{"class":992},[941,1657,1658],{"class":996}," tokenCache",[941,1660,1661],{"class":951},"()\n",[941,1663,1664,1666,1668,1671,1673,1676],{"class":943,"line":1003},[941,1665,1610],{"class":955},[941,1667,1015],{"class":951},[941,1669,1670],{"class":996},"delete",[941,1672,1179],{"class":951},[941,1674,1675],{"class":955},"rawToken",[941,1677,1185],{"class":951},[856,1679,1680],{},"Apart from the signed verification, newly generated token are cached, and verified in the verification process, meaning even if an access token passes the cryptographic verification, but doesn't exists in the cache, it fails verification.\nThis design allows you to revoke any valid access token, by simply deleting its cache.",[856,1682,1683,1684,1015],{},"Learn more in the ",[895,1685,1686],{"href":88},"access token page",[902,1688],{},[905,1690,91],{"id":1691},"refresh-tokens",[856,1693,1694,1695,1697],{},"Refresh tokens are opaque random 64 bytes hex strings. The service stores a SHA-256 hash of each token in MySQL alongside usage metadata. The raw token is sent to the client only once, as an ",[860,1696,886],{}," cookie, and never stored in plaintext.",[920,1699,1701],{"id":1700},"generating-a-refresh-token","Generating a refresh token",[932,1703,1705],{"className":934,"code":1704,"language":936,"meta":937,"style":937},"import { generateRefreshToken } from '@riavzon\u002Fauth'\n\nconst { raw, expiresAt } = await generateRefreshToken(\n  config.jwt.refresh_tokens.refresh_ttl,\n  user.id,\n  prevTs \u002F\u002F optional\n)\n\n\u002F\u002F Send `raw` to the client via Set-Cookie\n\u002F\u002F `expiresAt` is the Date at which the token expires\n",[860,1706,1707,1726,1730,1757,1779,1790,1798,1802,1806,1812],{"__ignoreMap":937},[941,1708,1709,1711,1713,1716,1718,1720,1722,1724],{"class":943,"line":944},[941,1710,948],{"class":947},[941,1712,952],{"class":951},[941,1714,1715],{"class":955},"generateRefreshToken",[941,1717,958],{"class":951},[941,1719,961],{"class":947},[941,1721,965],{"class":964},[941,1723,969],{"class":968},[941,1725,972],{"class":964},[941,1727,1728],{"class":943,"line":975},[941,1729,978],{"emptyLinePlaceholder":8},[941,1731,1732,1734,1736,1739,1741,1744,1746,1748,1751,1754],{"class":943,"line":981},[941,1733,985],{"class":984},[941,1735,952],{"class":951},[941,1737,1738],{"class":988},"raw",[941,1740,1079],{"class":951},[941,1742,1743],{"class":988},"expiresAt",[941,1745,958],{"class":951},[941,1747,1173],{"class":992},[941,1749,1750],{"class":947}," await",[941,1752,1753],{"class":996}," generateRefreshToken",[941,1755,1756],{"class":951},"(\n",[941,1758,1759,1762,1764,1767,1769,1772,1774,1777],{"class":943,"line":1003},[941,1760,1761],{"class":955},"  config",[941,1763,1015],{"class":951},[941,1765,1766],{"class":955},"jwt",[941,1768,1015],{"class":951},[941,1770,1771],{"class":955},"refresh_tokens",[941,1773,1015],{"class":951},[941,1775,1776],{"class":955},"refresh_ttl",[941,1778,1021],{"class":951},[941,1780,1781,1784,1786,1788],{"class":943,"line":1024},[941,1782,1783],{"class":955},"  user",[941,1785,1015],{"class":951},[941,1787,1018],{"class":955},[941,1789,1021],{"class":951},[941,1791,1792,1795],{"class":943,"line":1041},[941,1793,1794],{"class":955},"  prevTs",[941,1796,1797],{"class":1210}," \u002F\u002F optional\n",[941,1799,1800],{"class":943,"line":1060},[941,1801,1185],{"class":951},[941,1803,1804],{"class":943,"line":1092},[941,1805,978],{"emptyLinePlaceholder":8},[941,1807,1809],{"class":943,"line":1808},9,[941,1810,1811],{"class":1210},"\u002F\u002F Send `raw` to the client via Set-Cookie\n",[941,1813,1815],{"class":943,"line":1814},10,[941,1816,1817],{"class":1210},"\u002F\u002F `expiresAt` is the Date at which the token expires\n",[856,1819,1820],{},"When using the standalone service, refresh tokens are sent to clients when they:",[1100,1822,1823,1825,1827,1829],{},[1103,1824,1105],{},[1103,1826,1108],{},[1103,1828,1111],{},[1103,1830,1114],{},[920,1832,1834],{"id":1833},"verifying-a-refresh-token-for-library-users","Verifying a refresh token for library users",[856,1836,1837,1838,1841],{},"Use ",[860,1839,1840],{},"verifyRefreshToken"," for validation without token consumption. It can still perform side effects, such as invalidating expired tokens or deleting revoked token rows.",[932,1843,1845],{"className":934,"code":1844,"language":936,"meta":937,"style":937},"import { verifyRefreshToken } from '@riavzon\u002Fauth'\n\nconst result = await verifyRefreshToken(clientToken)\n\nif (result.valid) {\n  const { userId, visitor_id, sessionStartedAt, expiresAt } = result\n}\n",[860,1846,1847,1865,1869,1890,1894,1909,1938],{"__ignoreMap":937},[941,1848,1849,1851,1853,1855,1857,1859,1861,1863],{"class":943,"line":944},[941,1850,948],{"class":947},[941,1852,952],{"class":951},[941,1854,1840],{"class":955},[941,1856,958],{"class":951},[941,1858,961],{"class":947},[941,1860,965],{"class":964},[941,1862,969],{"class":968},[941,1864,972],{"class":964},[941,1866,1867],{"class":943,"line":975},[941,1868,978],{"emptyLinePlaceholder":8},[941,1870,1871,1873,1876,1878,1880,1883,1885,1888],{"class":943,"line":981},[941,1872,985],{"class":984},[941,1874,1875],{"class":988}," result",[941,1877,993],{"class":992},[941,1879,1750],{"class":947},[941,1881,1882],{"class":996}," verifyRefreshToken",[941,1884,1179],{"class":951},[941,1886,1887],{"class":955},"clientToken",[941,1889,1185],{"class":951},[941,1891,1892],{"class":943,"line":1003},[941,1893,978],{"emptyLinePlaceholder":8},[941,1895,1896,1898,1900,1903,1905,1907],{"class":943,"line":1024},[941,1897,1194],{"class":947},[941,1899,1197],{"class":951},[941,1901,1902],{"class":955},"result",[941,1904,1015],{"class":951},[941,1906,1158],{"class":955},[941,1908,1205],{"class":951},[941,1910,1911,1914,1916,1918,1920,1922,1924,1927,1929,1931,1933,1935],{"class":943,"line":1041},[941,1912,1913],{"class":984},"  const",[941,1915,952],{"class":951},[941,1917,1479],{"class":988},[941,1919,1079],{"class":951},[941,1921,1036],{"class":988},[941,1923,1079],{"class":951},[941,1925,1926],{"class":988},"sessionStartedAt",[941,1928,1079],{"class":951},[941,1930,1743],{"class":988},[941,1932,958],{"class":951},[941,1934,1173],{"class":992},[941,1936,1937],{"class":955}," result\n",[941,1939,1940],{"class":943,"line":1060},[941,1941,1221],{"class":951},[1943,1944,1945],"warning",{},[856,1946,1947,1949,1950],{},[860,1948,1840],{}," Is not recomended for production uses, its existent is solely for convenience, and quick verification.\nUse ",[860,1951,1952],{},"consumeAndVerifyRefreshToken",[920,1954,1956],{"id":1955},"consuming-a-refresh-token","Consuming a refresh token",[856,1958,1837,1959,1961,1962,1015],{},[860,1960,1952],{}," for verification, rotation and reuse detection.\nThis function marks the token as consumed after the first use. A second attempt with the same token revokes all sessions for that user and returns ",[860,1963,1964],{},"valid: false",[932,1966,1968],{"className":934,"code":1967,"language":936,"meta":937,"style":937},"import { consumeAndVerifyRefreshToken } from '@riavzon\u002Fauth'\n\nconst result = await consumeAndVerifyRefreshToken(clientToken)\n\nif (!result.valid) {\n  \u002F\u002F result.reason describes why verification failed\n}\n",[860,1969,1970,1988,1992,2011,2015,2031,2036],{"__ignoreMap":937},[941,1971,1972,1974,1976,1978,1980,1982,1984,1986],{"class":943,"line":944},[941,1973,948],{"class":947},[941,1975,952],{"class":951},[941,1977,1952],{"class":955},[941,1979,958],{"class":951},[941,1981,961],{"class":947},[941,1983,965],{"class":964},[941,1985,969],{"class":968},[941,1987,972],{"class":964},[941,1989,1990],{"class":943,"line":975},[941,1991,978],{"emptyLinePlaceholder":8},[941,1993,1994,1996,1998,2000,2002,2005,2007,2009],{"class":943,"line":981},[941,1995,985],{"class":984},[941,1997,1875],{"class":988},[941,1999,993],{"class":992},[941,2001,1750],{"class":947},[941,2003,2004],{"class":996}," consumeAndVerifyRefreshToken",[941,2006,1179],{"class":951},[941,2008,1887],{"class":955},[941,2010,1185],{"class":951},[941,2012,2013],{"class":943,"line":1003},[941,2014,978],{"emptyLinePlaceholder":8},[941,2016,2017,2019,2021,2023,2025,2027,2029],{"class":943,"line":1024},[941,2018,1194],{"class":947},[941,2020,1197],{"class":951},[941,2022,1200],{"class":992},[941,2024,1902],{"class":955},[941,2026,1015],{"class":951},[941,2028,1158],{"class":955},[941,2030,1205],{"class":951},[941,2032,2033],{"class":943,"line":1041},[941,2034,2035],{"class":1210},"  \u002F\u002F result.reason describes why verification failed\n",[941,2037,2038],{"class":943,"line":1060},[941,2039,1221],{"class":951},[856,2041,2042],{},"This is handled automatically for standalone service users.",[920,2044,2046],{"id":2045},"revoking-a-refresh-token","Revoking a refresh token",[856,2048,2049,2050,2053],{},"Logout and anomaly handlers call ",[860,2051,2052],{},"revokeRefreshToken"," to invalidate a specific session.",[932,2055,2057],{"className":934,"code":2056,"language":936,"meta":937,"style":937},"import { revokeRefreshToken } from '@riavzon\u002Fauth'\n\nconst { success } = await revokeRefreshToken(clientToken)\n",[860,2058,2059,2077,2081],{"__ignoreMap":937},[941,2060,2061,2063,2065,2067,2069,2071,2073,2075],{"class":943,"line":944},[941,2062,948],{"class":947},[941,2064,952],{"class":951},[941,2066,2052],{"class":955},[941,2068,958],{"class":951},[941,2070,961],{"class":947},[941,2072,965],{"class":964},[941,2074,969],{"class":968},[941,2076,972],{"class":964},[941,2078,2079],{"class":943,"line":975},[941,2080,978],{"emptyLinePlaceholder":8},[941,2082,2083,2085,2087,2090,2092,2094,2096,2099,2101,2103],{"class":943,"line":981},[941,2084,985],{"class":984},[941,2086,952],{"class":951},[941,2088,2089],{"class":988},"success",[941,2091,958],{"class":951},[941,2093,1173],{"class":992},[941,2095,1750],{"class":947},[941,2097,2098],{"class":996}," revokeRefreshToken",[941,2100,1179],{"class":951},[941,2102,1887],{"class":955},[941,2104,1185],{"class":951},[902,2106],{},[905,2108,2110],{"id":2109},"token-rotation","Token Rotation",[856,2112,2113,2114,2117],{},"Rotation happens only via the ",[860,2115,2116],{},"\u002Fauth\u002Fuser\u002Frefresh-session"," route and clients should call it directly with 2 credentials:",[1100,2119,2120,2127],{},[1103,2121,2122,2124,2125],{},[860,2123,862],{}," cookie - generated by the ",[860,2126,899],{},[1103,2128,2129,2130],{},"refresh token - the refresh token cookie ",[860,2131,2132],{},"session",[856,2134,2135,2136,2138,2139,2142,2143,2146,2147],{},"Anomalies such as reuse detection, invalid ",[860,2137,862],{},", or client IP range and fingerprint mismatches are flagged. Some anomalies trigger MFA (",[860,2140,2141],{},"202","), while others return immediate re-login (",[860,2144,2145],{},"401",") and may revoke refresh tokens. Learn more at ",[895,2148,2149],{"href":96},"anomalies",[856,2151,2152],{},"When the credentials are valid, and no anomalies are detected:",[1100,2154,2155,2158,2164],{},[1103,2156,2157],{},"The old refresh token is marked as consumed",[1103,2159,2160,2161,2163],{},"New refresh token is generated and sended to the client as a cookie, along side ",[860,2162,1308],{}," cookie",[1103,2165,2166,2167,2170],{},"New Access token is generated and sended to the client as a ",[860,2168,2169],{},"accessToken"," json field",[856,2172,2173],{},"Example success response:",[932,2175,2177],{"className":1320,"code":2176,"language":5,"meta":937,"style":937},"{\n    \"message\": \"Refresh & access tokens rotated\",\n    \"accessToken\": \"\u003Ctoken>\",\n     \"accessIat\": \"Date.now().toString()\"\n}\n",[860,2178,2179,2183,2203,2222,2242],{"__ignoreMap":937},[941,2180,2181],{"class":943,"line":944},[941,2182,1328],{"class":951},[941,2184,2185,2187,2190,2192,2194,2196,2199,2201],{"class":943,"line":975},[941,2186,1476],{"class":1333},[941,2188,2189],{"class":1337},"message",[941,2191,1071],{"class":1333},[941,2193,930],{"class":992},[941,2195,1344],{"class":964},[941,2197,2198],{"class":968},"Refresh & access tokens rotated",[941,2200,1071],{"class":964},[941,2202,1021],{"class":951},[941,2204,2205,2207,2209,2211,2213,2215,2218,2220],{"class":943,"line":981},[941,2206,1476],{"class":1333},[941,2208,2169],{"class":1337},[941,2210,1071],{"class":1333},[941,2212,930],{"class":992},[941,2214,1344],{"class":964},[941,2216,2217],{"class":968},"\u003Ctoken>",[941,2219,1071],{"class":964},[941,2221,1021],{"class":951},[941,2223,2224,2227,2230,2232,2234,2236,2239],{"class":943,"line":1003},[941,2225,2226],{"class":1333},"     \"",[941,2228,2229],{"class":1337},"accessIat",[941,2231,1071],{"class":1333},[941,2233,930],{"class":992},[941,2235,1344],{"class":964},[941,2237,2238],{"class":968},"Date.now().toString()",[941,2240,2241],{"class":964},"\"\n",[941,2243,2244],{"class":943,"line":1024},[941,2245,1221],{"class":951},[856,2247,2248],{},"You can also call the rotation helpers directly when you use the library:",[932,2250,2252],{"className":934,"code":2251,"language":936,"meta":937,"style":937},"import { rotateOneUseRefreshToken, rotateInPlaceRefreshToken } from '@riavzon\u002Fauth'\n\nawait rotateOneUseRefreshToken(config.jwt.refresh_tokens.refresh_ttl, userId, oldToken)\n\nawait rotateInPlaceRefreshToken(config.jwt.refresh_tokens.refresh_ttl, userId, oldToken)\n\nawait consumeAndVerifyRefreshToken(clientToken)\n",[860,2253,2254,2278,2282,2318,2322,2355,2359],{"__ignoreMap":937},[941,2255,2256,2258,2260,2263,2265,2268,2270,2272,2274,2276],{"class":943,"line":944},[941,2257,948],{"class":947},[941,2259,952],{"class":951},[941,2261,2262],{"class":955},"rotateOneUseRefreshToken",[941,2264,1079],{"class":951},[941,2266,2267],{"class":955},"rotateInPlaceRefreshToken",[941,2269,958],{"class":951},[941,2271,961],{"class":947},[941,2273,965],{"class":964},[941,2275,969],{"class":968},[941,2277,972],{"class":964},[941,2279,2280],{"class":943,"line":975},[941,2281,978],{"emptyLinePlaceholder":8},[941,2283,2284,2287,2290,2292,2295,2297,2299,2301,2303,2305,2307,2309,2311,2313,2316],{"class":943,"line":981},[941,2285,2286],{"class":947},"await",[941,2288,2289],{"class":996}," rotateOneUseRefreshToken",[941,2291,1179],{"class":951},[941,2293,2294],{"class":955},"config",[941,2296,1015],{"class":951},[941,2298,1766],{"class":955},[941,2300,1015],{"class":951},[941,2302,1771],{"class":955},[941,2304,1015],{"class":951},[941,2306,1776],{"class":955},[941,2308,1079],{"class":951},[941,2310,1479],{"class":955},[941,2312,1079],{"class":951},[941,2314,2315],{"class":955},"oldToken",[941,2317,1185],{"class":951},[941,2319,2320],{"class":943,"line":1003},[941,2321,978],{"emptyLinePlaceholder":8},[941,2323,2324,2326,2329,2331,2333,2335,2337,2339,2341,2343,2345,2347,2349,2351,2353],{"class":943,"line":1024},[941,2325,2286],{"class":947},[941,2327,2328],{"class":996}," rotateInPlaceRefreshToken",[941,2330,1179],{"class":951},[941,2332,2294],{"class":955},[941,2334,1015],{"class":951},[941,2336,1766],{"class":955},[941,2338,1015],{"class":951},[941,2340,1771],{"class":955},[941,2342,1015],{"class":951},[941,2344,1776],{"class":955},[941,2346,1079],{"class":951},[941,2348,1479],{"class":955},[941,2350,1079],{"class":951},[941,2352,2315],{"class":955},[941,2354,1185],{"class":951},[941,2356,2357],{"class":943,"line":1041},[941,2358,978],{"emptyLinePlaceholder":8},[941,2360,2361,2363,2365,2367,2369],{"class":943,"line":1060},[941,2362,2286],{"class":947},[941,2364,2004],{"class":996},[941,2366,1179],{"class":951},[941,2368,1887],{"class":955},[941,2370,1185],{"class":951},[905,2372,2374],{"id":2373},"reuse-detection","Reuse Detection",[856,2376,2377,2378,2380,2381,2383],{},"The system employs several mechanism to detect reuse and anomalies described in ",[895,2379,2149],{"href":96}," in details, in a brief, the system ties the token family to the user unique fingerprints, made available by the ",[860,2382,899],{}," and enhanced:",[856,2385,2386,2389],{},[865,2387,2388],{},"Scenario 1:"," An attacker got a valid refresh token \u002F access token.",[856,2391,2392,2393,2395],{},"In order to use this token, the attacker would need to perfectly copy the user fingerprints + the fingerprint identifier ",[860,2394,862],{},", to avoid an MFA challenge:",[2397,2398,2399,2402],"ol",{},[1103,2400,2401],{},"Attacker uses the token = fingerprint mismatch? MFA.",[1103,2403,2404,2405],{},"Attacker uses the token and the fingerprints is valid the token usage_count is now 1.\n",[1100,2406,2407,2410,2413],{},[1103,2408,2409],{},"Legitimate user tries to login\u002Frotate\u002Flogout or use the token.",[1103,2411,2412],{},"Reuse is detected.",[1103,2414,2415],{},"The account is locked and the user would need to login again, and complete an MFA challenge.",[856,2417,2418,2421],{},[865,2419,2420],{},"Scenario 2:"," An attacker obtains a refresh token that has already been rotated by the legitimate user.",[856,2423,2424],{},"In this \"stale token\" scenario, the attacker is immediately caught by the reuse detection logic:",[1100,2426,2427,2430,2433],{},[1103,2428,2429],{},"The moment the attacker attempts to use the previously rotated token, the system identifies it as a reuse violation.",[1103,2431,2432],{},"The system assumes the entire token family is compromised. It invalidates the attacker’s token and the legitimate user’s current session instantly.",[1103,2434,2435],{},"Both parties are forced out. The legitimate user is prompted to re-authenticate via a full login and MFA flow, effectively locking the attacker out of the account since they lack access to the user's secondary factors (Email\u002FMFA).",[2437,2438,2439],"style",{},"html pre.shiki code .sZ328, html code.shiki .sZ328{--shiki-light:#AF00DB;--shiki-default:#AF00DB;--shiki-dark:#FF79C6}html pre.shiki code .sDd4n, html code.shiki .sDd4n{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#F8F8F2}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 .s3JHE, html code.shiki .s3JHE{--shiki-light:#0070C1;--shiki-default:#0070C1;--shiki-dark:#F8F8F2}html pre.shiki code .saOXh, html code.shiki .saOXh{--shiki-light:#000000;--shiki-default:#000000;--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 .s34zl, html code.shiki .s34zl{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#FF79C6}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 .sghk6, html code.shiki .sghk6{--shiki-light:#008000;--shiki-default:#008000;--shiki-dark:#6272A4}html pre.shiki code .saJyd, html code.shiki .saJyd{--shiki-light:#0451A5;--shiki-default:#0451A5;--shiki-dark:#8BE9FE}html pre.shiki code .s_W10, html code.shiki .s_W10{--shiki-light:#0451A5;--shiki-default:#0451A5;--shiki-dark:#8BE9FD}html pre.shiki code .spgvN, html code.shiki .spgvN{--shiki-light:#098658;--shiki-default:#098658;--shiki-dark:#BD93F9}html pre.shiki code .sjR7W, html code.shiki .sjR7W{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#BD93F9}",{"title":937,"searchDepth":975,"depth":975,"links":2441},[2442,2448,2454,2455],{"id":907,"depth":975,"text":87,"children":2443},[2444,2445,2446,2447],{"id":922,"depth":981,"text":923},{"id":1117,"depth":981,"text":1118},{"id":1289,"depth":981,"text":1290},{"id":1610,"depth":981,"text":1611},{"id":1691,"depth":975,"text":91,"children":2449},[2450,2451,2452,2453],{"id":1700,"depth":981,"text":1701},{"id":1833,"depth":981,"text":1834},{"id":1955,"depth":981,"text":1956},{"id":2045,"depth":981,"text":2046},{"id":2109,"depth":975,"text":2110},{"id":2373,"depth":975,"text":2374},"How the IAM service generates, caches, verifies, rotates, and revokes JWT access tokens and MySQL-backed refresh tokens.","md",{},null,"---\ntitle: Tokens\ndescription: How the IAM service generates, caches, verifies, rotates, and revokes JWT access tokens and MySQL-backed refresh tokens.\nicon: i-lucide-key-round\n---\n\n\nThe IAM service uses a two token architecture and a `canary_id` cookie for anomalies detection. A short-lived **access token** and A long-lived **refresh token**.\nThe access token is sent as a json field to clients, while clients needs to send it back in a `Authorization: Bearer \u003Ctoken>` header for verification. \n\nRefresh tokens are long-lived, stored hashed with `sha-256` in MySQL and sent via an `httpOnly` cookie to clients. Clients needs to send this cookie back for verification.\n\nThe `canary_id` cookie, is generated by the [`bot-detector`](\u002Fdocs\u002Fbot-detection), and should be included by clients on any sensitive request. This cookie is tied to the token family, and invalid cookie will be flagged.\n\n---\n\n## Access Tokens\n\nAccess tokens are signed JWTs. The service signs them with the `jwt.jwt_secret_key` configured in `configuration()` and caches verified tokens in an LRU cache for the duration of their validity.\n\n### Generating an access token\n\nWhen using the service as a library, you can generate an access token with `generateAccessToken`:\n\n```ts\nimport { generateAccessToken } from '@riavzon\u002Fauth'\n\nconst token = generateAccessToken({\n  id: user.id,\n  visitor_id: user.visitor_id,\n  jti: crypto.randomUUID(),\n  roles: [\"user\", \"admin\"]\n})\n\n```\nWhen using the standalone service, access tokens are sent to clients when they:\n\n- Make an account\n- Login to their account\n- Try to rotate their session\n- Proof their identity via an MFA flow.\n\n### Verifying an access token\n\nWhen using the service as a library:\n\n```ts\nimport { verifyAccessToken } from '@riavzon\u002Fauth'\n\nconst { valid, payload, errorType } = verifyAccessToken(token)\n\nif (!valid) {\n  \u002F\u002F errorType is 'TokenExpiredError' for expired tokens\n  \u002F\u002F or a description string for other failures\n}\n```\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `valid` | `boolean` | Whether the token passed signature and expiry checks |\n| `payload` | `JwtPayload \\| undefined` | Decoded claims when valid |\n| `errorType` | `string \\| undefined` | Error description when invalid |\n\n### Token payload\n\nThe default payload includes `visitor`, `roles`, `sub`, `jti`, `iat`, and `exp`. Additional claims are merged from `jwt.access_tokens.payload` in the configuration.\n\n```json\n{\n  \"visitor\": \"vis_abc123\",\n  \"roles\": [\"user\", \"admin\"],\n  \"sub\": \"42\",\n  \"jti\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"iat\": 1710000000,\n  \"exp\": 1710000900\n}\n```\nWhen using the service directly, you should send access tokens to the `\u002Fsecret\u002Fdata` route.\nThis route requires the access token header, canary_id cookie, and the refresh token cookie.\n\nWhen verification passes, you get back a json data with the following fields:\n\n```json\n {\n    \"userId\": 1234,\n    \"authorized\": true,\n    \"ipAddress\": \"1.1.1.1\",\n    \"userAgent\":  \"client user agent\",\n    \"date\": \"iso formatted date\",\n    \"roles\": [\"admin\", \"user\", \"etc\"]\n  }\n```\n\n### Cache\n\nThe access token cache is an LRU cache keyed by the signed token string. Its size is controlled by `jwt.access_tokens.maxCacheEntries`. Import the cache directly if you need to inspect or clear it:\n\n```ts\nimport { tokenCache } from '@riavzon\u002Fauth'\n\nconst cache = tokenCache()\ncache.delete(rawToken)\n\n```\nApart from the signed verification, newly generated token are cached, and verified in the verification process, meaning even if an access token passes the cryptographic verification, but doesn't exists in the cache, it fails verification.\nThis design allows you to revoke any valid access token, by simply deleting its cache.\n\nLearn more in the [access token page](\u002Fdocs\u002Fiam\u002Fessentials\u002Faccess-tokens).\n\n---\n\n## Refresh Tokens\n\nRefresh tokens are opaque random 64 bytes hex strings. The service stores a SHA-256 hash of each token in MySQL alongside usage metadata. The raw token is sent to the client only once, as an `httpOnly` cookie, and never stored in plaintext.\n\n### Generating a refresh token\n\n```ts\nimport { generateRefreshToken } from '@riavzon\u002Fauth'\n\nconst { raw, expiresAt } = await generateRefreshToken(\n  config.jwt.refresh_tokens.refresh_ttl,\n  user.id,\n  prevTs \u002F\u002F optional\n)\n\n\u002F\u002F Send `raw` to the client via Set-Cookie\n\u002F\u002F `expiresAt` is the Date at which the token expires\n```\nWhen using the standalone service, refresh tokens are sent to clients when they:\n\n- Make an account\n- Login to their account\n- Try to rotate their session\n- Proof their identity via an MFA flow.\n\n\n### Verifying a refresh token for library users\n\nUse `verifyRefreshToken` for validation without token consumption. It can still perform side effects, such as invalidating expired tokens or deleting revoked token rows.\n\n```ts\nimport { verifyRefreshToken } from '@riavzon\u002Fauth'\n\nconst result = await verifyRefreshToken(clientToken)\n\nif (result.valid) {\n  const { userId, visitor_id, sessionStartedAt, expiresAt } = result\n}\n```\n\n::warning\n`verifyRefreshToken` Is not recomended for production uses, its existent is solely for convenience, and quick verification.\nUse `consumeAndVerifyRefreshToken`\n::\n\n### Consuming a refresh token\n\nUse `consumeAndVerifyRefreshToken` for verification, rotation and reuse detection. \nThis function marks the token as consumed after the first use. A second attempt with the same token revokes all sessions for that user and returns `valid: false`.\n\n```ts\nimport { consumeAndVerifyRefreshToken } from '@riavzon\u002Fauth'\n\nconst result = await consumeAndVerifyRefreshToken(clientToken)\n\nif (!result.valid) {\n  \u002F\u002F result.reason describes why verification failed\n}\n```\nThis is handled automatically for standalone service users.\n\n\n### Revoking a refresh token\n\nLogout and anomaly handlers call `revokeRefreshToken` to invalidate a specific session.\n\n```ts\nimport { revokeRefreshToken } from '@riavzon\u002Fauth'\n\nconst { success } = await revokeRefreshToken(clientToken)\n```\n\n--- \n\n## Token Rotation\nRotation happens only via the `\u002Fauth\u002Fuser\u002Frefresh-session` route and clients should call it directly with 2 credentials:\n\n- `canary_id` cookie - generated by the `bot-detector`\n- refresh token - the refresh token cookie `session`\n\nAnomalies such as reuse detection, invalid `canary_id`, or client IP range and fingerprint mismatches are flagged. Some anomalies trigger MFA (`202`), while others return immediate re-login (`401`) and may revoke refresh tokens. Learn more at [anomalies](\u002Fdocs\u002Fiam\u002Fessentials\u002Fanomalies)\n\nWhen the credentials are valid, and no anomalies are detected: \n- The old refresh token is marked as consumed\n- New refresh token is generated and sended to the client as a cookie, along side `iat` cookie\n- New Access token is generated and sended to the client as a `accessToken` json field\n\nExample success response: \n\n```json\n{\n    \"message\": \"Refresh & access tokens rotated\",\n    \"accessToken\": \"\u003Ctoken>\",\n     \"accessIat\": \"Date.now().toString()\"\n}\n```\n\nYou can also call the rotation helpers directly when you use the library:\n\n```ts\nimport { rotateOneUseRefreshToken, rotateInPlaceRefreshToken } from '@riavzon\u002Fauth'\n\nawait rotateOneUseRefreshToken(config.jwt.refresh_tokens.refresh_ttl, userId, oldToken)\n\nawait rotateInPlaceRefreshToken(config.jwt.refresh_tokens.refresh_ttl, userId, oldToken)\n\nawait consumeAndVerifyRefreshToken(clientToken)\n```\n\n\n## Reuse Detection\n\nThe system employs several mechanism to detect reuse and anomalies described in [anomalies](\u002Fdocs\u002Fiam\u002Fessentials\u002Fanomalies) in details, in a brief, the system ties the token family to the user unique fingerprints, made available by the `bot-detector` and enhanced:\n\n**Scenario 1:** An attacker got a valid refresh token \u002F access token.\n\nIn order to use this token, the attacker would need to perfectly copy the user fingerprints + the fingerprint identifier `canary_id`, to avoid an MFA challenge:\n\n1. Attacker uses the token = fingerprint mismatch? MFA.\n2. Attacker uses the token and the fingerprints is valid the token usage_count is now 1.\n   - Legitimate user tries to login\u002Frotate\u002Flogout or use the token. \n   - Reuse is detected.\n   - The account is locked and the user would need to login again, and complete an MFA challenge.\n\n**Scenario 2:** An attacker obtains a refresh token that has already been rotated by the legitimate user. \n\nIn this \"stale token\" scenario, the attacker is immediately caught by the reuse detection logic:\n\n- The moment the attacker attempts to use the previously rotated token, the system identifies it as a reuse violation.\n- The system assumes the entire token family is compromised. It invalidates the attacker’s token and the legitimate user’s current session instantly.\n- Both parties are forced out. The legitimate user is prompted to re-authenticate via a full login and MFA flow, effectively locking the attacker out of the account since they lack access to the user's secondary factors (Email\u002FMFA).\n",{"title":83,"description":2456},"kvjYapwcsELAbB1YI3zF3pQPNe1omDOFP5DILzyVhds",[2464,2465],{"title":77,"path":78,"stem":79,"children":-1},{"title":87,"path":88,"stem":89,"children":-1},{"id":851,"title":83,"body":2467,"description":2456,"extension":2457,"icon":21,"meta":3753,"module":2459,"navigation":8,"path":84,"rawbody":2460,"seo":3754,"stem":85,"__hash__":2462},{"type":853,"value":2468,"toc":3737},[2469,2479,2485,2493,2495,2497,2503,2505,2509,2617,2619,2629,2631,2633,2715,2765,2767,2783,2903,2907,2909,3039,3041,3045,3097,3099,3103,3105,3107,3111,3113,3211,3213,3223,3225,3229,3321,3329,3331,3337,3409,3411,3413,3417,3465,3467,3469,3473,3485,3495,3497,3509,3511,3575,3577,3691,3693,3699,3703,3707,3721,3725,3727,3735],[856,2470,858,2471,863,2473,868,2475,872,2477,876],{},[860,2472,862],{},[865,2474,867],{},[865,2476,871],{},[860,2478,875],{},[856,2480,879,2481,883,2483,887],{},[860,2482,882],{},[860,2484,886],{},[856,2486,890,2487,893,2489,900],{},[860,2488,862],{},[895,2490,2491],{"href":35},[860,2492,899],{},[902,2494],{},[905,2496,87],{"id":907},[856,2498,910,2499,914,2501,918],{},[860,2500,913],{},[860,2502,917],{},[920,2504,923],{"id":922},[856,2506,926,2507,930],{},[860,2508,929],{},[932,2510,2511],{"className":934,"code":935,"language":936,"meta":937,"style":937},[860,2512,2513,2531,2535,2547,2561,2575,2589,2613],{"__ignoreMap":937},[941,2514,2515,2517,2519,2521,2523,2525,2527,2529],{"class":943,"line":944},[941,2516,948],{"class":947},[941,2518,952],{"class":951},[941,2520,929],{"class":955},[941,2522,958],{"class":951},[941,2524,961],{"class":947},[941,2526,965],{"class":964},[941,2528,969],{"class":968},[941,2530,972],{"class":964},[941,2532,2533],{"class":943,"line":975},[941,2534,978],{"emptyLinePlaceholder":8},[941,2536,2537,2539,2541,2543,2545],{"class":943,"line":981},[941,2538,985],{"class":984},[941,2540,989],{"class":988},[941,2542,993],{"class":992},[941,2544,997],{"class":996},[941,2546,1000],{"class":951},[941,2548,2549,2551,2553,2555,2557,2559],{"class":943,"line":1003},[941,2550,1006],{"class":955},[941,2552,930],{"class":1009},[941,2554,1012],{"class":955},[941,2556,1015],{"class":951},[941,2558,1018],{"class":955},[941,2560,1021],{"class":951},[941,2562,2563,2565,2567,2569,2571,2573],{"class":943,"line":1024},[941,2564,1027],{"class":955},[941,2566,930],{"class":1009},[941,2568,1012],{"class":955},[941,2570,1015],{"class":951},[941,2572,1036],{"class":955},[941,2574,1021],{"class":951},[941,2576,2577,2579,2581,2583,2585,2587],{"class":943,"line":1041},[941,2578,1044],{"class":955},[941,2580,930],{"class":1009},[941,2582,1049],{"class":955},[941,2584,1015],{"class":951},[941,2586,1054],{"class":996},[941,2588,1057],{"class":951},[941,2590,2591,2593,2595,2597,2599,2601,2603,2605,2607,2609,2611],{"class":943,"line":1060},[941,2592,1063],{"class":955},[941,2594,930],{"class":1009},[941,2596,1068],{"class":951},[941,2598,1071],{"class":964},[941,2600,1074],{"class":968},[941,2602,1071],{"class":964},[941,2604,1079],{"class":951},[941,2606,1071],{"class":964},[941,2608,1084],{"class":968},[941,2610,1071],{"class":964},[941,2612,1089],{"class":951},[941,2614,2615],{"class":943,"line":1092},[941,2616,1095],{"class":951},[856,2618,1098],{},[1100,2620,2621,2623,2625,2627],{},[1103,2622,1105],{},[1103,2624,1108],{},[1103,2626,1111],{},[1103,2628,1114],{},[920,2630,1118],{"id":1117},[856,2632,1121],{},[932,2634,2635],{"className":934,"code":1124,"language":936,"meta":937,"style":937},[860,2636,2637,2655,2659,2687,2691,2703,2707,2711],{"__ignoreMap":937},[941,2638,2639,2641,2643,2645,2647,2649,2651,2653],{"class":943,"line":944},[941,2640,948],{"class":947},[941,2642,952],{"class":951},[941,2644,1135],{"class":955},[941,2646,958],{"class":951},[941,2648,961],{"class":947},[941,2650,965],{"class":964},[941,2652,969],{"class":968},[941,2654,972],{"class":964},[941,2656,2657],{"class":943,"line":975},[941,2658,978],{"emptyLinePlaceholder":8},[941,2660,2661,2663,2665,2667,2669,2671,2673,2675,2677,2679,2681,2683,2685],{"class":943,"line":981},[941,2662,985],{"class":984},[941,2664,952],{"class":951},[941,2666,1158],{"class":988},[941,2668,1079],{"class":951},[941,2670,1163],{"class":988},[941,2672,1079],{"class":951},[941,2674,1168],{"class":988},[941,2676,958],{"class":951},[941,2678,1173],{"class":992},[941,2680,1176],{"class":996},[941,2682,1179],{"class":951},[941,2684,1182],{"class":955},[941,2686,1185],{"class":951},[941,2688,2689],{"class":943,"line":1003},[941,2690,978],{"emptyLinePlaceholder":8},[941,2692,2693,2695,2697,2699,2701],{"class":943,"line":1024},[941,2694,1194],{"class":947},[941,2696,1197],{"class":951},[941,2698,1200],{"class":992},[941,2700,1158],{"class":955},[941,2702,1205],{"class":951},[941,2704,2705],{"class":943,"line":1041},[941,2706,1211],{"class":1210},[941,2708,2709],{"class":943,"line":1060},[941,2710,1216],{"class":1210},[941,2712,2713],{"class":943,"line":1092},[941,2714,1221],{"class":951},[1223,2716,2717,2727],{},[1226,2718,2719],{},[1229,2720,2721,2723,2725],{},[1232,2722,1234],{},[1232,2724,1237],{},[1232,2726,1240],{},[1242,2728,2729,2741,2753],{},[1229,2730,2731,2735,2739],{},[1247,2732,2733],{},[860,2734,1158],{},[1247,2736,2737],{},[860,2738,1255],{},[1247,2740,1258],{},[1229,2742,2743,2747,2751],{},[1247,2744,2745],{},[860,2746,1163],{},[1247,2748,2749],{},[860,2750,1269],{},[1247,2752,1272],{},[1229,2754,2755,2759,2763],{},[1247,2756,2757],{},[860,2758,1168],{},[1247,2760,2761],{},[860,2762,1283],{},[1247,2764,1286],{},[920,2766,1290],{"id":1289},[856,2768,1293,2769,1079,2771,1079,2773,1079,2775,1079,2777,1309,2779,1313,2781,1317],{},[860,2770,1296],{},[860,2772,1299],{},[860,2774,1302],{},[860,2776,1305],{},[860,2778,1308],{},[860,2780,1312],{},[860,2782,1316],{},[932,2784,2785],{"className":1320,"code":1321,"language":5,"meta":937,"style":937},[860,2786,2787,2791,2809,2837,2855,2873,2887,2899],{"__ignoreMap":937},[941,2788,2789],{"class":943,"line":944},[941,2790,1328],{"class":951},[941,2792,2793,2795,2797,2799,2801,2803,2805,2807],{"class":943,"line":975},[941,2794,1334],{"class":1333},[941,2796,1296],{"class":1337},[941,2798,1071],{"class":1333},[941,2800,930],{"class":992},[941,2802,1344],{"class":964},[941,2804,1347],{"class":968},[941,2806,1071],{"class":964},[941,2808,1021],{"class":951},[941,2810,2811,2813,2815,2817,2819,2821,2823,2825,2827,2829,2831,2833,2835],{"class":943,"line":981},[941,2812,1334],{"class":1333},[941,2814,1299],{"class":1337},[941,2816,1071],{"class":1333},[941,2818,930],{"class":992},[941,2820,1068],{"class":951},[941,2822,1071],{"class":964},[941,2824,1074],{"class":968},[941,2826,1071],{"class":964},[941,2828,1079],{"class":951},[941,2830,1071],{"class":964},[941,2832,1084],{"class":968},[941,2834,1071],{"class":964},[941,2836,1380],{"class":951},[941,2838,2839,2841,2843,2845,2847,2849,2851,2853],{"class":943,"line":1003},[941,2840,1334],{"class":1333},[941,2842,1302],{"class":1337},[941,2844,1071],{"class":1333},[941,2846,930],{"class":992},[941,2848,1344],{"class":964},[941,2850,1395],{"class":968},[941,2852,1071],{"class":964},[941,2854,1021],{"class":951},[941,2856,2857,2859,2861,2863,2865,2867,2869,2871],{"class":943,"line":1024},[941,2858,1334],{"class":1333},[941,2860,1305],{"class":1337},[941,2862,1071],{"class":1333},[941,2864,930],{"class":992},[941,2866,1344],{"class":964},[941,2868,1414],{"class":968},[941,2870,1071],{"class":964},[941,2872,1021],{"class":951},[941,2874,2875,2877,2879,2881,2883,2885],{"class":943,"line":1041},[941,2876,1334],{"class":1333},[941,2878,1308],{"class":1337},[941,2880,1071],{"class":1333},[941,2882,930],{"class":992},[941,2884,1432],{"class":1431},[941,2886,1021],{"class":951},[941,2888,2889,2891,2893,2895,2897],{"class":943,"line":1060},[941,2890,1334],{"class":1333},[941,2892,1312],{"class":1337},[941,2894,1071],{"class":1333},[941,2896,930],{"class":992},[941,2898,1447],{"class":1431},[941,2900,2901],{"class":943,"line":1092},[941,2902,1221],{"class":951},[856,2904,1454,2905,1458],{},[860,2906,1457],{},[856,2908,1461],{},[932,2910,2911],{"className":1320,"code":1464,"language":5,"meta":937,"style":937},[860,2912,2913,2917,2931,2945,2963,2981,2999,3035],{"__ignoreMap":937},[941,2914,2915],{"class":943,"line":944},[941,2916,1471],{"class":951},[941,2918,2919,2921,2923,2925,2927,2929],{"class":943,"line":975},[941,2920,1476],{"class":1333},[941,2922,1479],{"class":1337},[941,2924,1071],{"class":1333},[941,2926,930],{"class":992},[941,2928,1486],{"class":1431},[941,2930,1021],{"class":951},[941,2932,2933,2935,2937,2939,2941,2943],{"class":943,"line":981},[941,2934,1476],{"class":1333},[941,2936,1495],{"class":1337},[941,2938,1071],{"class":1333},[941,2940,930],{"class":992},[941,2942,1503],{"class":1502},[941,2944,1021],{"class":951},[941,2946,2947,2949,2951,2953,2955,2957,2959,2961],{"class":943,"line":1003},[941,2948,1476],{"class":1333},[941,2950,1512],{"class":1337},[941,2952,1071],{"class":1333},[941,2954,930],{"class":992},[941,2956,1344],{"class":964},[941,2958,1521],{"class":968},[941,2960,1071],{"class":964},[941,2962,1021],{"class":951},[941,2964,2965,2967,2969,2971,2973,2975,2977,2979],{"class":943,"line":1024},[941,2966,1476],{"class":1333},[941,2968,1532],{"class":1337},[941,2970,1071],{"class":1333},[941,2972,930],{"class":992},[941,2974,1334],{"class":964},[941,2976,1541],{"class":968},[941,2978,1071],{"class":964},[941,2980,1021],{"class":951},[941,2982,2983,2985,2987,2989,2991,2993,2995,2997],{"class":943,"line":1041},[941,2984,1476],{"class":1333},[941,2986,1552],{"class":1337},[941,2988,1071],{"class":1333},[941,2990,930],{"class":992},[941,2992,1344],{"class":964},[941,2994,1561],{"class":968},[941,2996,1071],{"class":964},[941,2998,1021],{"class":951},[941,3000,3001,3003,3005,3007,3009,3011,3013,3015,3017,3019,3021,3023,3025,3027,3029,3031,3033],{"class":943,"line":1060},[941,3002,1476],{"class":1333},[941,3004,1299],{"class":1337},[941,3006,1071],{"class":1333},[941,3008,930],{"class":992},[941,3010,1068],{"class":951},[941,3012,1071],{"class":964},[941,3014,1084],{"class":968},[941,3016,1071],{"class":964},[941,3018,1079],{"class":951},[941,3020,1071],{"class":964},[941,3022,1074],{"class":968},[941,3024,1071],{"class":964},[941,3026,1079],{"class":951},[941,3028,1071],{"class":964},[941,3030,1598],{"class":968},[941,3032,1071],{"class":964},[941,3034,1089],{"class":951},[941,3036,3037],{"class":943,"line":1092},[941,3038,1607],{"class":951},[920,3040,1611],{"id":1610},[856,3042,1614,3043,1618],{},[860,3044,1617],{},[932,3046,3047],{"className":934,"code":1621,"language":936,"meta":937,"style":937},[860,3048,3049,3067,3071,3083],{"__ignoreMap":937},[941,3050,3051,3053,3055,3057,3059,3061,3063,3065],{"class":943,"line":944},[941,3052,948],{"class":947},[941,3054,952],{"class":951},[941,3056,1632],{"class":955},[941,3058,958],{"class":951},[941,3060,961],{"class":947},[941,3062,965],{"class":964},[941,3064,969],{"class":968},[941,3066,972],{"class":964},[941,3068,3069],{"class":943,"line":975},[941,3070,978],{"emptyLinePlaceholder":8},[941,3072,3073,3075,3077,3079,3081],{"class":943,"line":981},[941,3074,985],{"class":984},[941,3076,1653],{"class":988},[941,3078,993],{"class":992},[941,3080,1658],{"class":996},[941,3082,1661],{"class":951},[941,3084,3085,3087,3089,3091,3093,3095],{"class":943,"line":1003},[941,3086,1610],{"class":955},[941,3088,1015],{"class":951},[941,3090,1670],{"class":996},[941,3092,1179],{"class":951},[941,3094,1675],{"class":955},[941,3096,1185],{"class":951},[856,3098,1680],{},[856,3100,1683,3101,1015],{},[895,3102,1686],{"href":88},[902,3104],{},[905,3106,91],{"id":1691},[856,3108,1694,3109,1697],{},[860,3110,886],{},[920,3112,1701],{"id":1700},[932,3114,3115],{"className":934,"code":1704,"language":936,"meta":937,"style":937},[860,3116,3117,3135,3139,3161,3179,3189,3195,3199,3203,3207],{"__ignoreMap":937},[941,3118,3119,3121,3123,3125,3127,3129,3131,3133],{"class":943,"line":944},[941,3120,948],{"class":947},[941,3122,952],{"class":951},[941,3124,1715],{"class":955},[941,3126,958],{"class":951},[941,3128,961],{"class":947},[941,3130,965],{"class":964},[941,3132,969],{"class":968},[941,3134,972],{"class":964},[941,3136,3137],{"class":943,"line":975},[941,3138,978],{"emptyLinePlaceholder":8},[941,3140,3141,3143,3145,3147,3149,3151,3153,3155,3157,3159],{"class":943,"line":981},[941,3142,985],{"class":984},[941,3144,952],{"class":951},[941,3146,1738],{"class":988},[941,3148,1079],{"class":951},[941,3150,1743],{"class":988},[941,3152,958],{"class":951},[941,3154,1173],{"class":992},[941,3156,1750],{"class":947},[941,3158,1753],{"class":996},[941,3160,1756],{"class":951},[941,3162,3163,3165,3167,3169,3171,3173,3175,3177],{"class":943,"line":1003},[941,3164,1761],{"class":955},[941,3166,1015],{"class":951},[941,3168,1766],{"class":955},[941,3170,1015],{"class":951},[941,3172,1771],{"class":955},[941,3174,1015],{"class":951},[941,3176,1776],{"class":955},[941,3178,1021],{"class":951},[941,3180,3181,3183,3185,3187],{"class":943,"line":1024},[941,3182,1783],{"class":955},[941,3184,1015],{"class":951},[941,3186,1018],{"class":955},[941,3188,1021],{"class":951},[941,3190,3191,3193],{"class":943,"line":1041},[941,3192,1794],{"class":955},[941,3194,1797],{"class":1210},[941,3196,3197],{"class":943,"line":1060},[941,3198,1185],{"class":951},[941,3200,3201],{"class":943,"line":1092},[941,3202,978],{"emptyLinePlaceholder":8},[941,3204,3205],{"class":943,"line":1808},[941,3206,1811],{"class":1210},[941,3208,3209],{"class":943,"line":1814},[941,3210,1817],{"class":1210},[856,3212,1820],{},[1100,3214,3215,3217,3219,3221],{},[1103,3216,1105],{},[1103,3218,1108],{},[1103,3220,1111],{},[1103,3222,1114],{},[920,3224,1834],{"id":1833},[856,3226,1837,3227,1841],{},[860,3228,1840],{},[932,3230,3231],{"className":934,"code":1844,"language":936,"meta":937,"style":937},[860,3232,3233,3251,3255,3273,3277,3291,3317],{"__ignoreMap":937},[941,3234,3235,3237,3239,3241,3243,3245,3247,3249],{"class":943,"line":944},[941,3236,948],{"class":947},[941,3238,952],{"class":951},[941,3240,1840],{"class":955},[941,3242,958],{"class":951},[941,3244,961],{"class":947},[941,3246,965],{"class":964},[941,3248,969],{"class":968},[941,3250,972],{"class":964},[941,3252,3253],{"class":943,"line":975},[941,3254,978],{"emptyLinePlaceholder":8},[941,3256,3257,3259,3261,3263,3265,3267,3269,3271],{"class":943,"line":981},[941,3258,985],{"class":984},[941,3260,1875],{"class":988},[941,3262,993],{"class":992},[941,3264,1750],{"class":947},[941,3266,1882],{"class":996},[941,3268,1179],{"class":951},[941,3270,1887],{"class":955},[941,3272,1185],{"class":951},[941,3274,3275],{"class":943,"line":1003},[941,3276,978],{"emptyLinePlaceholder":8},[941,3278,3279,3281,3283,3285,3287,3289],{"class":943,"line":1024},[941,3280,1194],{"class":947},[941,3282,1197],{"class":951},[941,3284,1902],{"class":955},[941,3286,1015],{"class":951},[941,3288,1158],{"class":955},[941,3290,1205],{"class":951},[941,3292,3293,3295,3297,3299,3301,3303,3305,3307,3309,3311,3313,3315],{"class":943,"line":1041},[941,3294,1913],{"class":984},[941,3296,952],{"class":951},[941,3298,1479],{"class":988},[941,3300,1079],{"class":951},[941,3302,1036],{"class":988},[941,3304,1079],{"class":951},[941,3306,1926],{"class":988},[941,3308,1079],{"class":951},[941,3310,1743],{"class":988},[941,3312,958],{"class":951},[941,3314,1173],{"class":992},[941,3316,1937],{"class":955},[941,3318,3319],{"class":943,"line":1060},[941,3320,1221],{"class":951},[1943,3322,3323],{},[856,3324,3325,1949,3327],{},[860,3326,1840],{},[860,3328,1952],{},[920,3330,1956],{"id":1955},[856,3332,1837,3333,1961,3335,1015],{},[860,3334,1952],{},[860,3336,1964],{},[932,3338,3339],{"className":934,"code":1967,"language":936,"meta":937,"style":937},[860,3340,3341,3359,3363,3381,3385,3401,3405],{"__ignoreMap":937},[941,3342,3343,3345,3347,3349,3351,3353,3355,3357],{"class":943,"line":944},[941,3344,948],{"class":947},[941,3346,952],{"class":951},[941,3348,1952],{"class":955},[941,3350,958],{"class":951},[941,3352,961],{"class":947},[941,3354,965],{"class":964},[941,3356,969],{"class":968},[941,3358,972],{"class":964},[941,3360,3361],{"class":943,"line":975},[941,3362,978],{"emptyLinePlaceholder":8},[941,3364,3365,3367,3369,3371,3373,3375,3377,3379],{"class":943,"line":981},[941,3366,985],{"class":984},[941,3368,1875],{"class":988},[941,3370,993],{"class":992},[941,3372,1750],{"class":947},[941,3374,2004],{"class":996},[941,3376,1179],{"class":951},[941,3378,1887],{"class":955},[941,3380,1185],{"class":951},[941,3382,3383],{"class":943,"line":1003},[941,3384,978],{"emptyLinePlaceholder":8},[941,3386,3387,3389,3391,3393,3395,3397,3399],{"class":943,"line":1024},[941,3388,1194],{"class":947},[941,3390,1197],{"class":951},[941,3392,1200],{"class":992},[941,3394,1902],{"class":955},[941,3396,1015],{"class":951},[941,3398,1158],{"class":955},[941,3400,1205],{"class":951},[941,3402,3403],{"class":943,"line":1041},[941,3404,2035],{"class":1210},[941,3406,3407],{"class":943,"line":1060},[941,3408,1221],{"class":951},[856,3410,2042],{},[920,3412,2046],{"id":2045},[856,3414,2049,3415,2053],{},[860,3416,2052],{},[932,3418,3419],{"className":934,"code":2056,"language":936,"meta":937,"style":937},[860,3420,3421,3439,3443],{"__ignoreMap":937},[941,3422,3423,3425,3427,3429,3431,3433,3435,3437],{"class":943,"line":944},[941,3424,948],{"class":947},[941,3426,952],{"class":951},[941,3428,2052],{"class":955},[941,3430,958],{"class":951},[941,3432,961],{"class":947},[941,3434,965],{"class":964},[941,3436,969],{"class":968},[941,3438,972],{"class":964},[941,3440,3441],{"class":943,"line":975},[941,3442,978],{"emptyLinePlaceholder":8},[941,3444,3445,3447,3449,3451,3453,3455,3457,3459,3461,3463],{"class":943,"line":981},[941,3446,985],{"class":984},[941,3448,952],{"class":951},[941,3450,2089],{"class":988},[941,3452,958],{"class":951},[941,3454,1173],{"class":992},[941,3456,1750],{"class":947},[941,3458,2098],{"class":996},[941,3460,1179],{"class":951},[941,3462,1887],{"class":955},[941,3464,1185],{"class":951},[902,3466],{},[905,3468,2110],{"id":2109},[856,3470,2113,3471,2117],{},[860,3472,2116],{},[1100,3474,3475,3481],{},[1103,3476,3477,2124,3479],{},[860,3478,862],{},[860,3480,899],{},[1103,3482,2129,3483],{},[860,3484,2132],{},[856,3486,2135,3487,2138,3489,2142,3491,2146,3493],{},[860,3488,862],{},[860,3490,2141],{},[860,3492,2145],{},[895,3494,2149],{"href":96},[856,3496,2152],{},[1100,3498,3499,3501,3505],{},[1103,3500,2157],{},[1103,3502,2160,3503,2163],{},[860,3504,1308],{},[1103,3506,2166,3507,2170],{},[860,3508,2169],{},[856,3510,2173],{},[932,3512,3513],{"className":1320,"code":2176,"language":5,"meta":937,"style":937},[860,3514,3515,3519,3537,3555,3571],{"__ignoreMap":937},[941,3516,3517],{"class":943,"line":944},[941,3518,1328],{"class":951},[941,3520,3521,3523,3525,3527,3529,3531,3533,3535],{"class":943,"line":975},[941,3522,1476],{"class":1333},[941,3524,2189],{"class":1337},[941,3526,1071],{"class":1333},[941,3528,930],{"class":992},[941,3530,1344],{"class":964},[941,3532,2198],{"class":968},[941,3534,1071],{"class":964},[941,3536,1021],{"class":951},[941,3538,3539,3541,3543,3545,3547,3549,3551,3553],{"class":943,"line":981},[941,3540,1476],{"class":1333},[941,3542,2169],{"class":1337},[941,3544,1071],{"class":1333},[941,3546,930],{"class":992},[941,3548,1344],{"class":964},[941,3550,2217],{"class":968},[941,3552,1071],{"class":964},[941,3554,1021],{"class":951},[941,3556,3557,3559,3561,3563,3565,3567,3569],{"class":943,"line":1003},[941,3558,2226],{"class":1333},[941,3560,2229],{"class":1337},[941,3562,1071],{"class":1333},[941,3564,930],{"class":992},[941,3566,1344],{"class":964},[941,3568,2238],{"class":968},[941,3570,2241],{"class":964},[941,3572,3573],{"class":943,"line":1024},[941,3574,1221],{"class":951},[856,3576,2248],{},[932,3578,3579],{"className":934,"code":2251,"language":936,"meta":937,"style":937},[860,3580,3581,3603,3607,3639,3643,3675,3679],{"__ignoreMap":937},[941,3582,3583,3585,3587,3589,3591,3593,3595,3597,3599,3601],{"class":943,"line":944},[941,3584,948],{"class":947},[941,3586,952],{"class":951},[941,3588,2262],{"class":955},[941,3590,1079],{"class":951},[941,3592,2267],{"class":955},[941,3594,958],{"class":951},[941,3596,961],{"class":947},[941,3598,965],{"class":964},[941,3600,969],{"class":968},[941,3602,972],{"class":964},[941,3604,3605],{"class":943,"line":975},[941,3606,978],{"emptyLinePlaceholder":8},[941,3608,3609,3611,3613,3615,3617,3619,3621,3623,3625,3627,3629,3631,3633,3635,3637],{"class":943,"line":981},[941,3610,2286],{"class":947},[941,3612,2289],{"class":996},[941,3614,1179],{"class":951},[941,3616,2294],{"class":955},[941,3618,1015],{"class":951},[941,3620,1766],{"class":955},[941,3622,1015],{"class":951},[941,3624,1771],{"class":955},[941,3626,1015],{"class":951},[941,3628,1776],{"class":955},[941,3630,1079],{"class":951},[941,3632,1479],{"class":955},[941,3634,1079],{"class":951},[941,3636,2315],{"class":955},[941,3638,1185],{"class":951},[941,3640,3641],{"class":943,"line":1003},[941,3642,978],{"emptyLinePlaceholder":8},[941,3644,3645,3647,3649,3651,3653,3655,3657,3659,3661,3663,3665,3667,3669,3671,3673],{"class":943,"line":1024},[941,3646,2286],{"class":947},[941,3648,2328],{"class":996},[941,3650,1179],{"class":951},[941,3652,2294],{"class":955},[941,3654,1015],{"class":951},[941,3656,1766],{"class":955},[941,3658,1015],{"class":951},[941,3660,1771],{"class":955},[941,3662,1015],{"class":951},[941,3664,1776],{"class":955},[941,3666,1079],{"class":951},[941,3668,1479],{"class":955},[941,3670,1079],{"class":951},[941,3672,2315],{"class":955},[941,3674,1185],{"class":951},[941,3676,3677],{"class":943,"line":1041},[941,3678,978],{"emptyLinePlaceholder":8},[941,3680,3681,3683,3685,3687,3689],{"class":943,"line":1060},[941,3682,2286],{"class":947},[941,3684,2004],{"class":996},[941,3686,1179],{"class":951},[941,3688,1887],{"class":955},[941,3690,1185],{"class":951},[905,3692,2374],{"id":2373},[856,3694,2377,3695,2380,3697,2383],{},[895,3696,2149],{"href":96},[860,3698,899],{},[856,3700,3701,2389],{},[865,3702,2388],{},[856,3704,2392,3705,2395],{},[860,3706,862],{},[2397,3708,3709,3711],{},[1103,3710,2401],{},[1103,3712,2404,3713],{},[1100,3714,3715,3717,3719],{},[1103,3716,2409],{},[1103,3718,2412],{},[1103,3720,2415],{},[856,3722,3723,2421],{},[865,3724,2420],{},[856,3726,2424],{},[1100,3728,3729,3731,3733],{},[1103,3730,2429],{},[1103,3732,2432],{},[1103,3734,2435],{},[2437,3736,2439],{},{"title":937,"searchDepth":975,"depth":975,"links":3738},[3739,3745,3751,3752],{"id":907,"depth":975,"text":87,"children":3740},[3741,3742,3743,3744],{"id":922,"depth":981,"text":923},{"id":1117,"depth":981,"text":1118},{"id":1289,"depth":981,"text":1290},{"id":1610,"depth":981,"text":1611},{"id":1691,"depth":975,"text":91,"children":3746},[3747,3748,3749,3750],{"id":1700,"depth":981,"text":1701},{"id":1833,"depth":981,"text":1834},{"id":1955,"depth":981,"text":1956},{"id":2045,"depth":981,"text":2046},{"id":2109,"depth":975,"text":2110},{"id":2373,"depth":975,"text":2374},{},{"title":83,"description":2456},1780436280101]