[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-post-nl-\u002Fblog\u002Fauthentication-strategies-\u002Fblog\u002Fauthentication-strategies":3,"blog-post-surround-nl-\u002Fblog\u002Fauthentication-strategies-\u002Fblog\u002Fauthentication-strategies":5067,"related-posts-nl-\u002Fblog\u002Fauthentication-strategies-\u002Fblog\u002Fauthentication-strategies":5076},{"id":4,"title":5,"authors":6,"badge":13,"body":15,"categories":5050,"date":5052,"description":5053,"extension":5054,"image":5055,"meta":5057,"navigation":152,"path":5058,"readingTime":441,"seo":5059,"stem":5060,"tags":5061,"__hash__":5066},"posts_nl\u002Fblog\u002F12.authentication-strategies.md","Authenticatie Strategieën: Veilige, Snelle Gebruikersbeheer",[7],{"name":8,"to":9,"avatar":10,"bio":12},"Marcel Posdijk","https:\u002F\u002Fx.com\u002Fmarcelposdijk",{"src":11},"\u002Fimages\u002Fteam\u002Fmarcel.jpg","Founder en lead developer bij Ludulicious B.V. met meer dan 25 jaar ervaring in webontwikkeling en software architectuur.",{"label":14},"Veiligheid",{"type":16,"value":17,"toc":5023},"minimark",[18,23,27,33,49,54,274,285,289,292,297,311,315,320,323,827,832,846,852,856,859,1802,1806,1820,1826,1830,1833,2620,2624,2638,2643,2647,2651,2654,2858,2862,2865,3771,3775,3789,3794,3798,3802,3805,3906,3910,3913,4655,4659,4673,4678,4682,4771,4775,4779,4790,4794,4804,4808,4819,4823,4831,4835,4846,4850,4853,4933,4937,4940,4943,4946,4965,4970,4978,5010,5013,5019],[19,20,22],"h2",{"id":21},"het-probleem-authenticatie-die-veilig-maar-langzaam-is","Het Probleem: Authenticatie Die Veilig Maar Langzaam Is",[24,25,26],"p",{},"In 2023 werkten we aan een project waar authenticatie veilig was maar gebruikers 3 seconden moesten wachten om in te loggen. Voor een moderne webapplicatie was dit onacceptabel—gebruikers verwachten instant authenticatie.",[24,28,29],{},[30,31,32],"strong",{},"De Uitdaging:",[34,35,36,40,43,46],"ul",{},[37,38,39],"li",{},"Veilige authenticatie vereist complexe flows",[37,41,42],{},"Performance en veiligheid moeten gebalanceerd worden",[37,44,45],{},"Meerdere authenticatie providers ondersteunen",[37,47,48],{},"Session management optimaliseren",[24,50,51],{},[30,52,53],{},"De Cijfers:",[55,56,61],"pre",{"className":57,"code":58,"language":59,"meta":60,"style":60},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F Langzame authenticatie flow\nconst loginTime = await measureLoginTime();\nconsole.log(`Login tijd: ${loginTime}ms`); \u002F\u002F 3000ms - te langzaam!\n\n\u002F\u002F Database queries tijdens login\nconst user = await db.query('SELECT * FROM users WHERE email = ?', [email]);\nconst permissions = await db.query('SELECT * FROM permissions WHERE user_id = ?', [user.id]);\nconst sessions = await db.query('SELECT * FROM sessions WHERE user_id = ?', [user.id]);\n","typescript","",[62,63,64,73,102,147,154,160,198,237],"code",{"__ignoreMap":60},[65,66,69],"span",{"class":67,"line":68},"line",1,[65,70,72],{"class":71},"sHwdD","\u002F\u002F Langzame authenticatie flow\n",[65,74,76,80,84,88,92,96,99],{"class":67,"line":75},2,[65,77,79],{"class":78},"spNyl","const",[65,81,83],{"class":82},"sTEyZ"," loginTime ",[65,85,87],{"class":86},"sMK4o","=",[65,89,91],{"class":90},"s7zQu"," await",[65,93,95],{"class":94},"s2Zo4"," measureLoginTime",[65,97,98],{"class":82},"()",[65,100,101],{"class":86},";\n",[65,103,105,108,111,114,117,120,124,127,130,133,136,138,141,144],{"class":67,"line":104},3,[65,106,107],{"class":82},"console",[65,109,110],{"class":86},".",[65,112,113],{"class":94},"log",[65,115,116],{"class":82},"(",[65,118,119],{"class":86},"`",[65,121,123],{"class":122},"sfazB","Login tijd: ",[65,125,126],{"class":86},"${",[65,128,129],{"class":82},"loginTime",[65,131,132],{"class":86},"}",[65,134,135],{"class":122},"ms",[65,137,119],{"class":86},[65,139,140],{"class":82},")",[65,142,143],{"class":86},";",[65,145,146],{"class":71}," \u002F\u002F 3000ms - te langzaam!\n",[65,148,150],{"class":67,"line":149},4,[65,151,153],{"emptyLinePlaceholder":152},true,"\n",[65,155,157],{"class":67,"line":156},5,[65,158,159],{"class":71},"\u002F\u002F Database queries tijdens login\n",[65,161,163,165,168,170,172,175,177,180,182,185,188,190,193,196],{"class":67,"line":162},6,[65,164,79],{"class":78},[65,166,167],{"class":82}," user ",[65,169,87],{"class":86},[65,171,91],{"class":90},[65,173,174],{"class":82}," db",[65,176,110],{"class":86},[65,178,179],{"class":94},"query",[65,181,116],{"class":82},[65,183,184],{"class":86},"'",[65,186,187],{"class":122},"SELECT * FROM users WHERE email = ?",[65,189,184],{"class":86},[65,191,192],{"class":86},",",[65,194,195],{"class":82}," [email])",[65,197,101],{"class":86},[65,199,201,203,206,208,210,212,214,216,218,220,223,225,227,230,232,235],{"class":67,"line":200},7,[65,202,79],{"class":78},[65,204,205],{"class":82}," permissions ",[65,207,87],{"class":86},[65,209,91],{"class":90},[65,211,174],{"class":82},[65,213,110],{"class":86},[65,215,179],{"class":94},[65,217,116],{"class":82},[65,219,184],{"class":86},[65,221,222],{"class":122},"SELECT * FROM permissions WHERE user_id = ?",[65,224,184],{"class":86},[65,226,192],{"class":86},[65,228,229],{"class":82}," [user",[65,231,110],{"class":86},[65,233,234],{"class":82},"id])",[65,236,101],{"class":86},[65,238,240,242,245,247,249,251,253,255,257,259,262,264,266,268,270,272],{"class":67,"line":239},8,[65,241,79],{"class":78},[65,243,244],{"class":82}," sessions ",[65,246,87],{"class":86},[65,248,91],{"class":90},[65,250,174],{"class":82},[65,252,110],{"class":86},[65,254,179],{"class":94},[65,256,116],{"class":82},[65,258,184],{"class":86},[65,260,261],{"class":122},"SELECT * FROM sessions WHERE user_id = ?",[65,263,184],{"class":86},[65,265,192],{"class":86},[65,267,229],{"class":82},[65,269,110],{"class":86},[65,271,234],{"class":82},[65,273,101],{"class":86},[24,275,276],{},[277,278],"img",{"alt":279,"className":280,"height":282,"src":283,"width":284},"Authenticatie strategieën",[281],"rounded-lg",600,"https:\u002F\u002Fpicsum.photos\u002Fid\u002F16\u002F1000\u002F600",1000,[19,286,288],{"id":287},"de-oorzaak-inefficiënte-authenticatie-implementatie","De Oorzaak: Inefficiënte Authenticatie Implementatie",[24,290,291],{},"Het probleem was duidelijk uit onze monitoring:",[24,293,294],{},[30,295,296],{},"Wat er gebeurde:",[34,298,299,302,305,308],{},[37,300,301],{},"Meerdere database queries per login",[37,303,304],{},"Geen caching van gebruikersdata",[37,306,307],{},"Inefficiënte session management",[37,309,310],{},"Geen optimalisatie voor performance",[19,312,314],{"id":313},"de-oplossing-multi-layer-authenticatie-strategie","De Oplossing: Multi-Layer Authenticatie Strategie",[316,317,319],"h3",{"id":318},"stap-1-oauth2-multi-provider-support","Stap 1: OAuth2 Multi-Provider Support",[24,321,322],{},"De eerste doorbraak kwam met OAuth2 multi-provider support:",[55,324,326],{"className":57,"code":325,"language":59,"meta":60,"style":60},"\u002F\u002F OAuth2 provider configuratie\ninterface AuthProvider {\n  name: string;\n  clientId: string;\n  clientSecret: string;\n  scope: string[];\n  endpoints: {\n    authorization: string;\n    token: string;\n    userInfo: string;\n  };\n}\n\nconst providers: AuthProvider[] = [\n  {\n    name: 'google',\n    clientId: process.env.GOOGLE_CLIENT_ID,\n    clientSecret: process.env.GOOGLE_CLIENT_SECRET,\n    scope: ['openid', 'email', 'profile'],\n    endpoints: {\n      authorization: 'https:\u002F\u002Faccounts.google.com\u002Fo\u002Foauth2\u002Fv2\u002Fauth',\n      token: 'https:\u002F\u002Foauth2.googleapis.com\u002Ftoken',\n      userInfo: 'https:\u002F\u002Fwww.googleapis.com\u002Foauth2\u002Fv2\u002Fuserinfo'\n    }\n  },\n  {\n    name: 'microsoft',\n    clientId: process.env.MICROSOFT_CLIENT_ID,\n    clientSecret: process.env.MICROSOFT_CLIENT_SECRET,\n    scope: ['openid', 'email', 'profile'],\n    endpoints: {\n      authorization: 'https:\u002F\u002Flogin.microsoftonline.com\u002Fcommon\u002Foauth2\u002Fv2.0\u002Fauthorize',\n      token: 'https:\u002F\u002Flogin.microsoftonline.com\u002Fcommon\u002Foauth2\u002Fv2.0\u002Ftoken',\n      userInfo: 'https:\u002F\u002Fgraph.microsoft.com\u002Fv1.0\u002Fme'\n    }\n  }\n];\n",[62,327,328,333,345,359,370,381,395,404,415,427,439,445,451,456,476,482,501,524,545,586,596,613,630,646,652,658,663,679,699,719,754,763,779,795,809,814,820],{"__ignoreMap":60},[65,329,330],{"class":67,"line":68},[65,331,332],{"class":71},"\u002F\u002F OAuth2 provider configuratie\n",[65,334,335,338,342],{"class":67,"line":75},[65,336,337],{"class":78},"interface",[65,339,341],{"class":340},"sBMFI"," AuthProvider",[65,343,344],{"class":86}," {\n",[65,346,347,351,354,357],{"class":67,"line":104},[65,348,350],{"class":349},"swJcz","  name",[65,352,353],{"class":86},":",[65,355,356],{"class":340}," string",[65,358,101],{"class":86},[65,360,361,364,366,368],{"class":67,"line":149},[65,362,363],{"class":349},"  clientId",[65,365,353],{"class":86},[65,367,356],{"class":340},[65,369,101],{"class":86},[65,371,372,375,377,379],{"class":67,"line":156},[65,373,374],{"class":349},"  clientSecret",[65,376,353],{"class":86},[65,378,356],{"class":340},[65,380,101],{"class":86},[65,382,383,386,388,390,393],{"class":67,"line":162},[65,384,385],{"class":349},"  scope",[65,387,353],{"class":86},[65,389,356],{"class":340},[65,391,392],{"class":82},"[]",[65,394,101],{"class":86},[65,396,397,400,402],{"class":67,"line":200},[65,398,399],{"class":349},"  endpoints",[65,401,353],{"class":86},[65,403,344],{"class":86},[65,405,406,409,411,413],{"class":67,"line":239},[65,407,408],{"class":349},"    authorization",[65,410,353],{"class":86},[65,412,356],{"class":340},[65,414,101],{"class":86},[65,416,418,421,423,425],{"class":67,"line":417},9,[65,419,420],{"class":349},"    token",[65,422,353],{"class":86},[65,424,356],{"class":340},[65,426,101],{"class":86},[65,428,430,433,435,437],{"class":67,"line":429},10,[65,431,432],{"class":349},"    userInfo",[65,434,353],{"class":86},[65,436,356],{"class":340},[65,438,101],{"class":86},[65,440,442],{"class":67,"line":441},11,[65,443,444],{"class":86},"  };\n",[65,446,448],{"class":67,"line":447},12,[65,449,450],{"class":86},"}\n",[65,452,454],{"class":67,"line":453},13,[65,455,153],{"emptyLinePlaceholder":152},[65,457,459,461,464,466,468,471,473],{"class":67,"line":458},14,[65,460,79],{"class":78},[65,462,463],{"class":82}," providers",[65,465,353],{"class":86},[65,467,341],{"class":340},[65,469,470],{"class":82},"[] ",[65,472,87],{"class":86},[65,474,475],{"class":82}," [\n",[65,477,479],{"class":67,"line":478},15,[65,480,481],{"class":86},"  {\n",[65,483,485,488,490,493,496,498],{"class":67,"line":484},16,[65,486,487],{"class":349},"    name",[65,489,353],{"class":86},[65,491,492],{"class":86}," '",[65,494,495],{"class":122},"google",[65,497,184],{"class":86},[65,499,500],{"class":86},",\n",[65,502,504,507,509,512,514,517,519,522],{"class":67,"line":503},17,[65,505,506],{"class":349},"    clientId",[65,508,353],{"class":86},[65,510,511],{"class":82}," process",[65,513,110],{"class":86},[65,515,516],{"class":82},"env",[65,518,110],{"class":86},[65,520,521],{"class":82},"GOOGLE_CLIENT_ID",[65,523,500],{"class":86},[65,525,527,530,532,534,536,538,540,543],{"class":67,"line":526},18,[65,528,529],{"class":349},"    clientSecret",[65,531,353],{"class":86},[65,533,511],{"class":82},[65,535,110],{"class":86},[65,537,516],{"class":82},[65,539,110],{"class":86},[65,541,542],{"class":82},"GOOGLE_CLIENT_SECRET",[65,544,500],{"class":86},[65,546,548,551,553,556,558,561,563,565,567,570,572,574,576,579,581,584],{"class":67,"line":547},19,[65,549,550],{"class":349},"    scope",[65,552,353],{"class":86},[65,554,555],{"class":82}," [",[65,557,184],{"class":86},[65,559,560],{"class":122},"openid",[65,562,184],{"class":86},[65,564,192],{"class":86},[65,566,492],{"class":86},[65,568,569],{"class":122},"email",[65,571,184],{"class":86},[65,573,192],{"class":86},[65,575,492],{"class":86},[65,577,578],{"class":122},"profile",[65,580,184],{"class":86},[65,582,583],{"class":82},"]",[65,585,500],{"class":86},[65,587,589,592,594],{"class":67,"line":588},20,[65,590,591],{"class":349},"    endpoints",[65,593,353],{"class":86},[65,595,344],{"class":86},[65,597,599,602,604,606,609,611],{"class":67,"line":598},21,[65,600,601],{"class":349},"      authorization",[65,603,353],{"class":86},[65,605,492],{"class":86},[65,607,608],{"class":122},"https:\u002F\u002Faccounts.google.com\u002Fo\u002Foauth2\u002Fv2\u002Fauth",[65,610,184],{"class":86},[65,612,500],{"class":86},[65,614,616,619,621,623,626,628],{"class":67,"line":615},22,[65,617,618],{"class":349},"      token",[65,620,353],{"class":86},[65,622,492],{"class":86},[65,624,625],{"class":122},"https:\u002F\u002Foauth2.googleapis.com\u002Ftoken",[65,627,184],{"class":86},[65,629,500],{"class":86},[65,631,633,636,638,640,643],{"class":67,"line":632},23,[65,634,635],{"class":349},"      userInfo",[65,637,353],{"class":86},[65,639,492],{"class":86},[65,641,642],{"class":122},"https:\u002F\u002Fwww.googleapis.com\u002Foauth2\u002Fv2\u002Fuserinfo",[65,644,645],{"class":86},"'\n",[65,647,649],{"class":67,"line":648},24,[65,650,651],{"class":86},"    }\n",[65,653,655],{"class":67,"line":654},25,[65,656,657],{"class":86},"  },\n",[65,659,661],{"class":67,"line":660},26,[65,662,481],{"class":86},[65,664,666,668,670,672,675,677],{"class":67,"line":665},27,[65,667,487],{"class":349},[65,669,353],{"class":86},[65,671,492],{"class":86},[65,673,674],{"class":122},"microsoft",[65,676,184],{"class":86},[65,678,500],{"class":86},[65,680,682,684,686,688,690,692,694,697],{"class":67,"line":681},28,[65,683,506],{"class":349},[65,685,353],{"class":86},[65,687,511],{"class":82},[65,689,110],{"class":86},[65,691,516],{"class":82},[65,693,110],{"class":86},[65,695,696],{"class":82},"MICROSOFT_CLIENT_ID",[65,698,500],{"class":86},[65,700,702,704,706,708,710,712,714,717],{"class":67,"line":701},29,[65,703,529],{"class":349},[65,705,353],{"class":86},[65,707,511],{"class":82},[65,709,110],{"class":86},[65,711,516],{"class":82},[65,713,110],{"class":86},[65,715,716],{"class":82},"MICROSOFT_CLIENT_SECRET",[65,718,500],{"class":86},[65,720,722,724,726,728,730,732,734,736,738,740,742,744,746,748,750,752],{"class":67,"line":721},30,[65,723,550],{"class":349},[65,725,353],{"class":86},[65,727,555],{"class":82},[65,729,184],{"class":86},[65,731,560],{"class":122},[65,733,184],{"class":86},[65,735,192],{"class":86},[65,737,492],{"class":86},[65,739,569],{"class":122},[65,741,184],{"class":86},[65,743,192],{"class":86},[65,745,492],{"class":86},[65,747,578],{"class":122},[65,749,184],{"class":86},[65,751,583],{"class":82},[65,753,500],{"class":86},[65,755,757,759,761],{"class":67,"line":756},31,[65,758,591],{"class":349},[65,760,353],{"class":86},[65,762,344],{"class":86},[65,764,766,768,770,772,775,777],{"class":67,"line":765},32,[65,767,601],{"class":349},[65,769,353],{"class":86},[65,771,492],{"class":86},[65,773,774],{"class":122},"https:\u002F\u002Flogin.microsoftonline.com\u002Fcommon\u002Foauth2\u002Fv2.0\u002Fauthorize",[65,776,184],{"class":86},[65,778,500],{"class":86},[65,780,782,784,786,788,791,793],{"class":67,"line":781},33,[65,783,618],{"class":349},[65,785,353],{"class":86},[65,787,492],{"class":86},[65,789,790],{"class":122},"https:\u002F\u002Flogin.microsoftonline.com\u002Fcommon\u002Foauth2\u002Fv2.0\u002Ftoken",[65,792,184],{"class":86},[65,794,500],{"class":86},[65,796,798,800,802,804,807],{"class":67,"line":797},34,[65,799,635],{"class":349},[65,801,353],{"class":86},[65,803,492],{"class":86},[65,805,806],{"class":122},"https:\u002F\u002Fgraph.microsoft.com\u002Fv1.0\u002Fme",[65,808,645],{"class":86},[65,810,812],{"class":67,"line":811},35,[65,813,651],{"class":86},[65,815,817],{"class":67,"line":816},36,[65,818,819],{"class":86},"  }\n",[65,821,823,825],{"class":67,"line":822},37,[65,824,583],{"class":82},[65,826,101],{"class":86},[24,828,829],{},[30,830,831],{},"Waarom Dit Werkt:",[34,833,834,837,840,843],{},[37,835,836],{},"Ondersteunt meerdere OAuth2 providers",[37,838,839],{},"Unified authenticatie interface",[37,841,842],{},"Gebruikers kunnen kiezen hoe ze willen inloggen",[37,844,845],{},"Vermindert wachtwoord gerelateerde problemen",[24,847,848,851],{},[30,849,850],{},"Immediate Resultaat:"," Login tijd verbeterde naar 1.5 seconden (2x verbetering)",[316,853,855],{"id":854},"stap-2-geoptimaliseerde-session-management","Stap 2: Geoptimaliseerde Session Management",[24,857,858],{},"Met betere OAuth2 support werd session management de volgende bottleneck:",[55,860,862],{"className":57,"code":861,"language":59,"meta":60,"style":60},"\u002F\u002F Geoptimaliseerde session management\ninterface Session {\n  id: string;\n  userId: string;\n  provider: string;\n  expiresAt: Date;\n  refreshToken?: string;\n  metadata: SessionMetadata;\n}\n\nclass SessionManager {\n  private redis: Redis;\n  private db: Database;\n\n  async createSession(user: User, provider: string): Promise\u003CSession> {\n    const sessionId = generateSecureId();\n    const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); \u002F\u002F 24 uur\n    \n    const session: Session = {\n      id: sessionId,\n      userId: user.id,\n      provider,\n      expiresAt,\n      metadata: {\n        ip: user.lastIp,\n        userAgent: user.userAgent,\n        createdAt: new Date()\n      }\n    };\n\n    \u002F\u002F Cache session in Redis voor snelle toegang\n    await this.redis.setex(\n      `session:${sessionId}`,\n      24 * 60 * 60, \u002F\u002F 24 uur TTL\n      JSON.stringify(session)\n    );\n\n    \u002F\u002F Persist in database voor backup\n    await this.db.query(\n      'INSERT INTO sessions (id, user_id, provider, expires_at, metadata) VALUES (?, ?, ?, ?, ?)',\n      [sessionId, user.id, provider, expiresAt, JSON.stringify(session.metadata)]\n    );\n\n    return session;\n  }\n\n  async validateSession(sessionId: string): Promise\u003CSession | null> {\n    \u002F\u002F Probeer eerst Redis cache\n    const cached = await this.redis.get(`session:${sessionId}`);\n    if (cached) {\n      return JSON.parse(cached);\n    }\n\n    \u002F\u002F Fallback naar database\n    const result = await this.db.query(\n      'SELECT * FROM sessions WHERE id = ? AND expires_at > NOW()',\n      [sessionId]\n    );\n\n    if (result.length === 0) {\n      return null;\n    }\n\n    const session = result[0];\n    \n    \u002F\u002F Cache voor volgende keer\n    await this.redis.setex(\n      `session:${sessionId}`,\n      24 * 60 * 60,\n      JSON.stringify(session)\n    );\n\n    return session;\n  }\n}\n",[62,863,864,869,878,889,900,911,923,935,947,951,955,965,980,993,997,1042,1060,1116,1121,1136,1147,1164,1171,1178,1187,1203,1219,1233,1238,1243,1247,1252,1271,1289,1307,1325,1332,1336,1342,1358,1371,1416,1423,1428,1438,1443,1448,1482,1488,1525,1543,1564,1569,1574,1580,1602,1614,1624,1631,1636,1661,1669,1674,1679,1700,1705,1711,1726,1741,1756,1771,1778,1783,1792,1797],{"__ignoreMap":60},[65,865,866],{"class":67,"line":68},[65,867,868],{"class":71},"\u002F\u002F Geoptimaliseerde session management\n",[65,870,871,873,876],{"class":67,"line":75},[65,872,337],{"class":78},[65,874,875],{"class":340}," Session",[65,877,344],{"class":86},[65,879,880,883,885,887],{"class":67,"line":104},[65,881,882],{"class":349},"  id",[65,884,353],{"class":86},[65,886,356],{"class":340},[65,888,101],{"class":86},[65,890,891,894,896,898],{"class":67,"line":149},[65,892,893],{"class":349},"  userId",[65,895,353],{"class":86},[65,897,356],{"class":340},[65,899,101],{"class":86},[65,901,902,905,907,909],{"class":67,"line":156},[65,903,904],{"class":349},"  provider",[65,906,353],{"class":86},[65,908,356],{"class":340},[65,910,101],{"class":86},[65,912,913,916,918,921],{"class":67,"line":162},[65,914,915],{"class":349},"  expiresAt",[65,917,353],{"class":86},[65,919,920],{"class":340}," Date",[65,922,101],{"class":86},[65,924,925,928,931,933],{"class":67,"line":200},[65,926,927],{"class":349},"  refreshToken",[65,929,930],{"class":86},"?:",[65,932,356],{"class":340},[65,934,101],{"class":86},[65,936,937,940,942,945],{"class":67,"line":239},[65,938,939],{"class":349},"  metadata",[65,941,353],{"class":86},[65,943,944],{"class":340}," SessionMetadata",[65,946,101],{"class":86},[65,948,949],{"class":67,"line":417},[65,950,450],{"class":86},[65,952,953],{"class":67,"line":429},[65,954,153],{"emptyLinePlaceholder":152},[65,956,957,960,963],{"class":67,"line":441},[65,958,959],{"class":78},"class",[65,961,962],{"class":340}," SessionManager",[65,964,344],{"class":86},[65,966,967,970,973,975,978],{"class":67,"line":447},[65,968,969],{"class":78},"  private",[65,971,972],{"class":349}," redis",[65,974,353],{"class":86},[65,976,977],{"class":340}," Redis",[65,979,101],{"class":86},[65,981,982,984,986,988,991],{"class":67,"line":453},[65,983,969],{"class":78},[65,985,174],{"class":349},[65,987,353],{"class":86},[65,989,990],{"class":340}," Database",[65,992,101],{"class":86},[65,994,995],{"class":67,"line":458},[65,996,153],{"emptyLinePlaceholder":152},[65,998,999,1002,1005,1007,1011,1013,1016,1018,1021,1023,1025,1028,1031,1034,1037,1040],{"class":67,"line":478},[65,1000,1001],{"class":78},"  async",[65,1003,1004],{"class":349}," createSession",[65,1006,116],{"class":86},[65,1008,1010],{"class":1009},"sHdIc","user",[65,1012,353],{"class":86},[65,1014,1015],{"class":340}," User",[65,1017,192],{"class":86},[65,1019,1020],{"class":1009}," provider",[65,1022,353],{"class":86},[65,1024,356],{"class":340},[65,1026,1027],{"class":86},"):",[65,1029,1030],{"class":340}," Promise",[65,1032,1033],{"class":86},"\u003C",[65,1035,1036],{"class":340},"Session",[65,1038,1039],{"class":86},">",[65,1041,344],{"class":86},[65,1043,1044,1047,1050,1053,1056,1058],{"class":67,"line":484},[65,1045,1046],{"class":78},"    const",[65,1048,1049],{"class":82}," sessionId",[65,1051,1052],{"class":86}," =",[65,1054,1055],{"class":94}," generateSecureId",[65,1057,98],{"class":349},[65,1059,101],{"class":86},[65,1061,1062,1064,1067,1069,1072,1074,1076,1079,1081,1084,1087,1090,1094,1097,1100,1102,1104,1106,1109,1111,1113],{"class":67,"line":503},[65,1063,1046],{"class":78},[65,1065,1066],{"class":82}," expiresAt",[65,1068,1052],{"class":86},[65,1070,1071],{"class":86}," new",[65,1073,920],{"class":94},[65,1075,116],{"class":349},[65,1077,1078],{"class":82},"Date",[65,1080,110],{"class":86},[65,1082,1083],{"class":94},"now",[65,1085,1086],{"class":349},"() ",[65,1088,1089],{"class":86},"+",[65,1091,1093],{"class":1092},"sbssI"," 24",[65,1095,1096],{"class":86}," *",[65,1098,1099],{"class":1092}," 60",[65,1101,1096],{"class":86},[65,1103,1099],{"class":1092},[65,1105,1096],{"class":86},[65,1107,1108],{"class":1092}," 1000",[65,1110,140],{"class":349},[65,1112,143],{"class":86},[65,1114,1115],{"class":71}," \u002F\u002F 24 uur\n",[65,1117,1118],{"class":67,"line":526},[65,1119,1120],{"class":349},"    \n",[65,1122,1123,1125,1128,1130,1132,1134],{"class":67,"line":547},[65,1124,1046],{"class":78},[65,1126,1127],{"class":82}," session",[65,1129,353],{"class":86},[65,1131,875],{"class":340},[65,1133,1052],{"class":86},[65,1135,344],{"class":86},[65,1137,1138,1141,1143,1145],{"class":67,"line":588},[65,1139,1140],{"class":349},"      id",[65,1142,353],{"class":86},[65,1144,1049],{"class":82},[65,1146,500],{"class":86},[65,1148,1149,1152,1154,1157,1159,1162],{"class":67,"line":598},[65,1150,1151],{"class":349},"      userId",[65,1153,353],{"class":86},[65,1155,1156],{"class":82}," user",[65,1158,110],{"class":86},[65,1160,1161],{"class":82},"id",[65,1163,500],{"class":86},[65,1165,1166,1169],{"class":67,"line":615},[65,1167,1168],{"class":82},"      provider",[65,1170,500],{"class":86},[65,1172,1173,1176],{"class":67,"line":632},[65,1174,1175],{"class":82},"      expiresAt",[65,1177,500],{"class":86},[65,1179,1180,1183,1185],{"class":67,"line":648},[65,1181,1182],{"class":349},"      metadata",[65,1184,353],{"class":86},[65,1186,344],{"class":86},[65,1188,1189,1192,1194,1196,1198,1201],{"class":67,"line":654},[65,1190,1191],{"class":349},"        ip",[65,1193,353],{"class":86},[65,1195,1156],{"class":82},[65,1197,110],{"class":86},[65,1199,1200],{"class":82},"lastIp",[65,1202,500],{"class":86},[65,1204,1205,1208,1210,1212,1214,1217],{"class":67,"line":660},[65,1206,1207],{"class":349},"        userAgent",[65,1209,353],{"class":86},[65,1211,1156],{"class":82},[65,1213,110],{"class":86},[65,1215,1216],{"class":82},"userAgent",[65,1218,500],{"class":86},[65,1220,1221,1224,1226,1228,1230],{"class":67,"line":665},[65,1222,1223],{"class":349},"        createdAt",[65,1225,353],{"class":86},[65,1227,1071],{"class":86},[65,1229,920],{"class":94},[65,1231,1232],{"class":349},"()\n",[65,1234,1235],{"class":67,"line":681},[65,1236,1237],{"class":86},"      }\n",[65,1239,1240],{"class":67,"line":701},[65,1241,1242],{"class":86},"    };\n",[65,1244,1245],{"class":67,"line":721},[65,1246,153],{"emptyLinePlaceholder":152},[65,1248,1249],{"class":67,"line":756},[65,1250,1251],{"class":71},"    \u002F\u002F Cache session in Redis voor snelle toegang\n",[65,1253,1254,1257,1260,1263,1265,1268],{"class":67,"line":765},[65,1255,1256],{"class":90},"    await",[65,1258,1259],{"class":86}," this.",[65,1261,1262],{"class":82},"redis",[65,1264,110],{"class":86},[65,1266,1267],{"class":94},"setex",[65,1269,1270],{"class":349},"(\n",[65,1272,1273,1276,1279,1281,1284,1287],{"class":67,"line":781},[65,1274,1275],{"class":86},"      `",[65,1277,1278],{"class":122},"session:",[65,1280,126],{"class":86},[65,1282,1283],{"class":82},"sessionId",[65,1285,1286],{"class":86},"}`",[65,1288,500],{"class":86},[65,1290,1291,1294,1296,1298,1300,1302,1304],{"class":67,"line":797},[65,1292,1293],{"class":1092},"      24",[65,1295,1096],{"class":86},[65,1297,1099],{"class":1092},[65,1299,1096],{"class":86},[65,1301,1099],{"class":1092},[65,1303,192],{"class":86},[65,1305,1306],{"class":71}," \u002F\u002F 24 uur TTL\n",[65,1308,1309,1312,1314,1317,1319,1322],{"class":67,"line":811},[65,1310,1311],{"class":82},"      JSON",[65,1313,110],{"class":86},[65,1315,1316],{"class":94},"stringify",[65,1318,116],{"class":349},[65,1320,1321],{"class":82},"session",[65,1323,1324],{"class":349},")\n",[65,1326,1327,1330],{"class":67,"line":816},[65,1328,1329],{"class":349},"    )",[65,1331,101],{"class":86},[65,1333,1334],{"class":67,"line":822},[65,1335,153],{"emptyLinePlaceholder":152},[65,1337,1339],{"class":67,"line":1338},38,[65,1340,1341],{"class":71},"    \u002F\u002F Persist in database voor backup\n",[65,1343,1345,1347,1349,1352,1354,1356],{"class":67,"line":1344},39,[65,1346,1256],{"class":90},[65,1348,1259],{"class":86},[65,1350,1351],{"class":82},"db",[65,1353,110],{"class":86},[65,1355,179],{"class":94},[65,1357,1270],{"class":349},[65,1359,1361,1364,1367,1369],{"class":67,"line":1360},40,[65,1362,1363],{"class":86},"      '",[65,1365,1366],{"class":122},"INSERT INTO sessions (id, user_id, provider, expires_at, metadata) VALUES (?, ?, ?, ?, ?)",[65,1368,184],{"class":86},[65,1370,500],{"class":86},[65,1372,1374,1377,1379,1381,1383,1385,1387,1389,1391,1393,1395,1397,1400,1402,1404,1406,1408,1410,1413],{"class":67,"line":1373},41,[65,1375,1376],{"class":349},"      [",[65,1378,1283],{"class":82},[65,1380,192],{"class":86},[65,1382,1156],{"class":82},[65,1384,110],{"class":86},[65,1386,1161],{"class":82},[65,1388,192],{"class":86},[65,1390,1020],{"class":82},[65,1392,192],{"class":86},[65,1394,1066],{"class":82},[65,1396,192],{"class":86},[65,1398,1399],{"class":82}," JSON",[65,1401,110],{"class":86},[65,1403,1316],{"class":94},[65,1405,116],{"class":349},[65,1407,1321],{"class":82},[65,1409,110],{"class":86},[65,1411,1412],{"class":82},"metadata",[65,1414,1415],{"class":349},")]\n",[65,1417,1419,1421],{"class":67,"line":1418},42,[65,1420,1329],{"class":349},[65,1422,101],{"class":86},[65,1424,1426],{"class":67,"line":1425},43,[65,1427,153],{"emptyLinePlaceholder":152},[65,1429,1431,1434,1436],{"class":67,"line":1430},44,[65,1432,1433],{"class":90},"    return",[65,1435,1127],{"class":82},[65,1437,101],{"class":86},[65,1439,1441],{"class":67,"line":1440},45,[65,1442,819],{"class":86},[65,1444,1446],{"class":67,"line":1445},46,[65,1447,153],{"emptyLinePlaceholder":152},[65,1449,1451,1453,1456,1458,1460,1462,1464,1466,1468,1470,1472,1475,1478,1480],{"class":67,"line":1450},47,[65,1452,1001],{"class":78},[65,1454,1455],{"class":349}," validateSession",[65,1457,116],{"class":86},[65,1459,1283],{"class":1009},[65,1461,353],{"class":86},[65,1463,356],{"class":340},[65,1465,1027],{"class":86},[65,1467,1030],{"class":340},[65,1469,1033],{"class":86},[65,1471,1036],{"class":340},[65,1473,1474],{"class":86}," |",[65,1476,1477],{"class":340}," null",[65,1479,1039],{"class":86},[65,1481,344],{"class":86},[65,1483,1485],{"class":67,"line":1484},48,[65,1486,1487],{"class":71},"    \u002F\u002F Probeer eerst Redis cache\n",[65,1489,1491,1493,1496,1498,1500,1502,1504,1506,1509,1511,1513,1515,1517,1519,1521,1523],{"class":67,"line":1490},49,[65,1492,1046],{"class":78},[65,1494,1495],{"class":82}," cached",[65,1497,1052],{"class":86},[65,1499,91],{"class":90},[65,1501,1259],{"class":86},[65,1503,1262],{"class":82},[65,1505,110],{"class":86},[65,1507,1508],{"class":94},"get",[65,1510,116],{"class":349},[65,1512,119],{"class":86},[65,1514,1278],{"class":122},[65,1516,126],{"class":86},[65,1518,1283],{"class":82},[65,1520,1286],{"class":86},[65,1522,140],{"class":349},[65,1524,101],{"class":86},[65,1526,1528,1531,1534,1537,1540],{"class":67,"line":1527},50,[65,1529,1530],{"class":90},"    if",[65,1532,1533],{"class":349}," (",[65,1535,1536],{"class":82},"cached",[65,1538,1539],{"class":349},") ",[65,1541,1542],{"class":86},"{\n",[65,1544,1546,1549,1551,1553,1556,1558,1560,1562],{"class":67,"line":1545},51,[65,1547,1548],{"class":90},"      return",[65,1550,1399],{"class":82},[65,1552,110],{"class":86},[65,1554,1555],{"class":94},"parse",[65,1557,116],{"class":349},[65,1559,1536],{"class":82},[65,1561,140],{"class":349},[65,1563,101],{"class":86},[65,1565,1567],{"class":67,"line":1566},52,[65,1568,651],{"class":86},[65,1570,1572],{"class":67,"line":1571},53,[65,1573,153],{"emptyLinePlaceholder":152},[65,1575,1577],{"class":67,"line":1576},54,[65,1578,1579],{"class":71},"    \u002F\u002F Fallback naar database\n",[65,1581,1583,1585,1588,1590,1592,1594,1596,1598,1600],{"class":67,"line":1582},55,[65,1584,1046],{"class":78},[65,1586,1587],{"class":82}," result",[65,1589,1052],{"class":86},[65,1591,91],{"class":90},[65,1593,1259],{"class":86},[65,1595,1351],{"class":82},[65,1597,110],{"class":86},[65,1599,179],{"class":94},[65,1601,1270],{"class":349},[65,1603,1605,1607,1610,1612],{"class":67,"line":1604},56,[65,1606,1363],{"class":86},[65,1608,1609],{"class":122},"SELECT * FROM sessions WHERE id = ? AND expires_at > NOW()",[65,1611,184],{"class":86},[65,1613,500],{"class":86},[65,1615,1617,1619,1621],{"class":67,"line":1616},57,[65,1618,1376],{"class":349},[65,1620,1283],{"class":82},[65,1622,1623],{"class":349},"]\n",[65,1625,1627,1629],{"class":67,"line":1626},58,[65,1628,1329],{"class":349},[65,1630,101],{"class":86},[65,1632,1634],{"class":67,"line":1633},59,[65,1635,153],{"emptyLinePlaceholder":152},[65,1637,1639,1641,1643,1646,1648,1651,1654,1657,1659],{"class":67,"line":1638},60,[65,1640,1530],{"class":90},[65,1642,1533],{"class":349},[65,1644,1645],{"class":82},"result",[65,1647,110],{"class":86},[65,1649,1650],{"class":82},"length",[65,1652,1653],{"class":86}," ===",[65,1655,1656],{"class":1092}," 0",[65,1658,1539],{"class":349},[65,1660,1542],{"class":86},[65,1662,1664,1666],{"class":67,"line":1663},61,[65,1665,1548],{"class":90},[65,1667,1668],{"class":86}," null;\n",[65,1670,1672],{"class":67,"line":1671},62,[65,1673,651],{"class":86},[65,1675,1677],{"class":67,"line":1676},63,[65,1678,153],{"emptyLinePlaceholder":152},[65,1680,1682,1684,1686,1688,1690,1693,1696,1698],{"class":67,"line":1681},64,[65,1683,1046],{"class":78},[65,1685,1127],{"class":82},[65,1687,1052],{"class":86},[65,1689,1587],{"class":82},[65,1691,1692],{"class":349},"[",[65,1694,1695],{"class":1092},"0",[65,1697,583],{"class":349},[65,1699,101],{"class":86},[65,1701,1703],{"class":67,"line":1702},65,[65,1704,1120],{"class":349},[65,1706,1708],{"class":67,"line":1707},66,[65,1709,1710],{"class":71},"    \u002F\u002F Cache voor volgende keer\n",[65,1712,1714,1716,1718,1720,1722,1724],{"class":67,"line":1713},67,[65,1715,1256],{"class":90},[65,1717,1259],{"class":86},[65,1719,1262],{"class":82},[65,1721,110],{"class":86},[65,1723,1267],{"class":94},[65,1725,1270],{"class":349},[65,1727,1729,1731,1733,1735,1737,1739],{"class":67,"line":1728},68,[65,1730,1275],{"class":86},[65,1732,1278],{"class":122},[65,1734,126],{"class":86},[65,1736,1283],{"class":82},[65,1738,1286],{"class":86},[65,1740,500],{"class":86},[65,1742,1744,1746,1748,1750,1752,1754],{"class":67,"line":1743},69,[65,1745,1293],{"class":1092},[65,1747,1096],{"class":86},[65,1749,1099],{"class":1092},[65,1751,1096],{"class":86},[65,1753,1099],{"class":1092},[65,1755,500],{"class":86},[65,1757,1759,1761,1763,1765,1767,1769],{"class":67,"line":1758},70,[65,1760,1311],{"class":82},[65,1762,110],{"class":86},[65,1764,1316],{"class":94},[65,1766,116],{"class":349},[65,1768,1321],{"class":82},[65,1770,1324],{"class":349},[65,1772,1774,1776],{"class":67,"line":1773},71,[65,1775,1329],{"class":349},[65,1777,101],{"class":86},[65,1779,1781],{"class":67,"line":1780},72,[65,1782,153],{"emptyLinePlaceholder":152},[65,1784,1786,1788,1790],{"class":67,"line":1785},73,[65,1787,1433],{"class":90},[65,1789,1127],{"class":82},[65,1791,101],{"class":86},[65,1793,1795],{"class":67,"line":1794},74,[65,1796,819],{"class":86},[65,1798,1800],{"class":67,"line":1799},75,[65,1801,450],{"class":86},[24,1803,1804],{},[30,1805,831],{},[34,1807,1808,1811,1814,1817],{},[37,1809,1810],{},"Redis caching voor snelle session validatie",[37,1812,1813],{},"Database backup voor betrouwbaarheid",[37,1815,1816],{},"Automatische TTL voor session cleanup",[37,1818,1819],{},"Metadata tracking voor security",[24,1821,1822,1825],{},[30,1823,1824],{},"Resultaat:"," Session validatie verbeterde naar 50ms (60x verbetering)",[316,1827,1829],{"id":1828},"stap-3-two-factor-authentication","Stap 3: Two-Factor Authentication",[24,1831,1832],{},"Met betere session management werd security de volgende focus:",[55,1834,1836],{"className":57,"code":1835,"language":59,"meta":60,"style":60},"\u002F\u002F Two-Factor Authentication implementatie\ninterface TwoFactorAuth {\n  enabled: boolean;\n  methods: ('totp' | 'sms' | 'email')[];\n  backupCodes: string[];\n}\n\nclass TwoFactorManager {\n  private totp: TOTP;\n  private sms: SMSProvider;\n  private email: EmailProvider;\n\n  async enable2FA(userId: string, method: 'totp' | 'sms' | 'email'): Promise\u003CTwoFactorAuth> {\n    const secret = generateSecret();\n    const backupCodes = generateBackupCodes(10);\n\n    const twoFactorAuth: TwoFactorAuth = {\n      enabled: true,\n      methods: [method],\n      backupCodes\n    };\n\n    \u002F\u002F Sla 2FA configuratie op\n    await this.db.query(\n      'INSERT INTO two_factor_auth (user_id, method, secret, backup_codes) VALUES (?, ?, ?, ?)',\n      [userId, method, secret, JSON.stringify(backupCodes)]\n    );\n\n    return twoFactorAuth;\n  }\n\n  async verify2FA(userId: string, code: string): Promise\u003Cboolean> {\n    const result = await this.db.query(\n      'SELECT * FROM two_factor_auth WHERE user_id = ?',\n      [userId]\n    );\n\n    if (result.length === 0) {\n      return false;\n    }\n\n    const twoFactorAuth = result[0];\n    \n    \u002F\u002F Controleer TOTP code\n    if (twoFactorAuth.method === 'totp') {\n      return this.totp.verify(code, twoFactorAuth.secret);\n    }\n\n    \u002F\u002F Controleer backup code\n    const backupCodes = JSON.parse(twoFactorAuth.backup_codes);\n    if (backupCodes.includes(code)) {\n      \u002F\u002F Verwijder gebruikte backup code\n      const updatedCodes = backupCodes.filter(c => c !== code);\n      await this.db.query(\n        'UPDATE two_factor_auth SET backup_codes = ? WHERE user_id = ?',\n        [JSON.stringify(updatedCodes), userId]\n      );\n      return true;\n    }\n\n    return false;\n  }\n}\n",[62,1837,1838,1843,1852,1864,1902,1915,1919,1923,1932,1946,1960,1974,1978,2036,2052,2073,2077,2092,2105,2121,2126,2130,2134,2139,2153,2164,2193,2199,2203,2211,2215,2219,2256,2276,2287,2295,2301,2305,2325,2334,2338,2342,2360,2364,2369,2394,2424,2428,2432,2437,2464,2486,2491,2528,2543,2555,2581,2588,2596,2600,2604,2612,2616],{"__ignoreMap":60},[65,1839,1840],{"class":67,"line":68},[65,1841,1842],{"class":71},"\u002F\u002F Two-Factor Authentication implementatie\n",[65,1844,1845,1847,1850],{"class":67,"line":75},[65,1846,337],{"class":78},[65,1848,1849],{"class":340}," TwoFactorAuth",[65,1851,344],{"class":86},[65,1853,1854,1857,1859,1862],{"class":67,"line":104},[65,1855,1856],{"class":349},"  enabled",[65,1858,353],{"class":86},[65,1860,1861],{"class":340}," boolean",[65,1863,101],{"class":86},[65,1865,1866,1869,1871,1873,1875,1878,1880,1882,1884,1887,1889,1891,1893,1895,1897,1900],{"class":67,"line":149},[65,1867,1868],{"class":349},"  methods",[65,1870,353],{"class":86},[65,1872,1533],{"class":82},[65,1874,184],{"class":86},[65,1876,1877],{"class":122},"totp",[65,1879,184],{"class":86},[65,1881,1474],{"class":86},[65,1883,492],{"class":86},[65,1885,1886],{"class":122},"sms",[65,1888,184],{"class":86},[65,1890,1474],{"class":86},[65,1892,492],{"class":86},[65,1894,569],{"class":122},[65,1896,184],{"class":86},[65,1898,1899],{"class":82},")[]",[65,1901,101],{"class":86},[65,1903,1904,1907,1909,1911,1913],{"class":67,"line":156},[65,1905,1906],{"class":349},"  backupCodes",[65,1908,353],{"class":86},[65,1910,356],{"class":340},[65,1912,392],{"class":82},[65,1914,101],{"class":86},[65,1916,1917],{"class":67,"line":162},[65,1918,450],{"class":86},[65,1920,1921],{"class":67,"line":200},[65,1922,153],{"emptyLinePlaceholder":152},[65,1924,1925,1927,1930],{"class":67,"line":239},[65,1926,959],{"class":78},[65,1928,1929],{"class":340}," TwoFactorManager",[65,1931,344],{"class":86},[65,1933,1934,1936,1939,1941,1944],{"class":67,"line":417},[65,1935,969],{"class":78},[65,1937,1938],{"class":349}," totp",[65,1940,353],{"class":86},[65,1942,1943],{"class":340}," TOTP",[65,1945,101],{"class":86},[65,1947,1948,1950,1953,1955,1958],{"class":67,"line":429},[65,1949,969],{"class":78},[65,1951,1952],{"class":349}," sms",[65,1954,353],{"class":86},[65,1956,1957],{"class":340}," SMSProvider",[65,1959,101],{"class":86},[65,1961,1962,1964,1967,1969,1972],{"class":67,"line":441},[65,1963,969],{"class":78},[65,1965,1966],{"class":349}," email",[65,1968,353],{"class":86},[65,1970,1971],{"class":340}," EmailProvider",[65,1973,101],{"class":86},[65,1975,1976],{"class":67,"line":447},[65,1977,153],{"emptyLinePlaceholder":152},[65,1979,1980,1982,1985,1987,1990,1992,1994,1996,1999,2001,2003,2005,2007,2009,2011,2013,2015,2017,2019,2021,2023,2025,2027,2029,2032,2034],{"class":67,"line":453},[65,1981,1001],{"class":78},[65,1983,1984],{"class":349}," enable2FA",[65,1986,116],{"class":86},[65,1988,1989],{"class":1009},"userId",[65,1991,353],{"class":86},[65,1993,356],{"class":340},[65,1995,192],{"class":86},[65,1997,1998],{"class":1009}," method",[65,2000,353],{"class":86},[65,2002,492],{"class":86},[65,2004,1877],{"class":122},[65,2006,184],{"class":86},[65,2008,1474],{"class":86},[65,2010,492],{"class":86},[65,2012,1886],{"class":122},[65,2014,184],{"class":86},[65,2016,1474],{"class":86},[65,2018,492],{"class":86},[65,2020,569],{"class":122},[65,2022,184],{"class":86},[65,2024,1027],{"class":86},[65,2026,1030],{"class":340},[65,2028,1033],{"class":86},[65,2030,2031],{"class":340},"TwoFactorAuth",[65,2033,1039],{"class":86},[65,2035,344],{"class":86},[65,2037,2038,2040,2043,2045,2048,2050],{"class":67,"line":458},[65,2039,1046],{"class":78},[65,2041,2042],{"class":82}," secret",[65,2044,1052],{"class":86},[65,2046,2047],{"class":94}," generateSecret",[65,2049,98],{"class":349},[65,2051,101],{"class":86},[65,2053,2054,2056,2059,2061,2064,2066,2069,2071],{"class":67,"line":478},[65,2055,1046],{"class":78},[65,2057,2058],{"class":82}," backupCodes",[65,2060,1052],{"class":86},[65,2062,2063],{"class":94}," generateBackupCodes",[65,2065,116],{"class":349},[65,2067,2068],{"class":1092},"10",[65,2070,140],{"class":349},[65,2072,101],{"class":86},[65,2074,2075],{"class":67,"line":484},[65,2076,153],{"emptyLinePlaceholder":152},[65,2078,2079,2081,2084,2086,2088,2090],{"class":67,"line":503},[65,2080,1046],{"class":78},[65,2082,2083],{"class":82}," twoFactorAuth",[65,2085,353],{"class":86},[65,2087,1849],{"class":340},[65,2089,1052],{"class":86},[65,2091,344],{"class":86},[65,2093,2094,2097,2099,2103],{"class":67,"line":526},[65,2095,2096],{"class":349},"      enabled",[65,2098,353],{"class":86},[65,2100,2102],{"class":2101},"sfNiH"," true",[65,2104,500],{"class":86},[65,2106,2107,2110,2112,2114,2117,2119],{"class":67,"line":547},[65,2108,2109],{"class":349},"      methods",[65,2111,353],{"class":86},[65,2113,555],{"class":349},[65,2115,2116],{"class":82},"method",[65,2118,583],{"class":349},[65,2120,500],{"class":86},[65,2122,2123],{"class":67,"line":588},[65,2124,2125],{"class":82},"      backupCodes\n",[65,2127,2128],{"class":67,"line":598},[65,2129,1242],{"class":86},[65,2131,2132],{"class":67,"line":615},[65,2133,153],{"emptyLinePlaceholder":152},[65,2135,2136],{"class":67,"line":632},[65,2137,2138],{"class":71},"    \u002F\u002F Sla 2FA configuratie op\n",[65,2140,2141,2143,2145,2147,2149,2151],{"class":67,"line":648},[65,2142,1256],{"class":90},[65,2144,1259],{"class":86},[65,2146,1351],{"class":82},[65,2148,110],{"class":86},[65,2150,179],{"class":94},[65,2152,1270],{"class":349},[65,2154,2155,2157,2160,2162],{"class":67,"line":654},[65,2156,1363],{"class":86},[65,2158,2159],{"class":122},"INSERT INTO two_factor_auth (user_id, method, secret, backup_codes) VALUES (?, ?, ?, ?)",[65,2161,184],{"class":86},[65,2163,500],{"class":86},[65,2165,2166,2168,2170,2172,2174,2176,2178,2180,2182,2184,2186,2188,2191],{"class":67,"line":660},[65,2167,1376],{"class":349},[65,2169,1989],{"class":82},[65,2171,192],{"class":86},[65,2173,1998],{"class":82},[65,2175,192],{"class":86},[65,2177,2042],{"class":82},[65,2179,192],{"class":86},[65,2181,1399],{"class":82},[65,2183,110],{"class":86},[65,2185,1316],{"class":94},[65,2187,116],{"class":349},[65,2189,2190],{"class":82},"backupCodes",[65,2192,1415],{"class":349},[65,2194,2195,2197],{"class":67,"line":665},[65,2196,1329],{"class":349},[65,2198,101],{"class":86},[65,2200,2201],{"class":67,"line":681},[65,2202,153],{"emptyLinePlaceholder":152},[65,2204,2205,2207,2209],{"class":67,"line":701},[65,2206,1433],{"class":90},[65,2208,2083],{"class":82},[65,2210,101],{"class":86},[65,2212,2213],{"class":67,"line":721},[65,2214,819],{"class":86},[65,2216,2217],{"class":67,"line":756},[65,2218,153],{"emptyLinePlaceholder":152},[65,2220,2221,2223,2226,2228,2230,2232,2234,2236,2239,2241,2243,2245,2247,2249,2252,2254],{"class":67,"line":765},[65,2222,1001],{"class":78},[65,2224,2225],{"class":349}," verify2FA",[65,2227,116],{"class":86},[65,2229,1989],{"class":1009},[65,2231,353],{"class":86},[65,2233,356],{"class":340},[65,2235,192],{"class":86},[65,2237,2238],{"class":1009}," code",[65,2240,353],{"class":86},[65,2242,356],{"class":340},[65,2244,1027],{"class":86},[65,2246,1030],{"class":340},[65,2248,1033],{"class":86},[65,2250,2251],{"class":340},"boolean",[65,2253,1039],{"class":86},[65,2255,344],{"class":86},[65,2257,2258,2260,2262,2264,2266,2268,2270,2272,2274],{"class":67,"line":781},[65,2259,1046],{"class":78},[65,2261,1587],{"class":82},[65,2263,1052],{"class":86},[65,2265,91],{"class":90},[65,2267,1259],{"class":86},[65,2269,1351],{"class":82},[65,2271,110],{"class":86},[65,2273,179],{"class":94},[65,2275,1270],{"class":349},[65,2277,2278,2280,2283,2285],{"class":67,"line":797},[65,2279,1363],{"class":86},[65,2281,2282],{"class":122},"SELECT * FROM two_factor_auth WHERE user_id = ?",[65,2284,184],{"class":86},[65,2286,500],{"class":86},[65,2288,2289,2291,2293],{"class":67,"line":811},[65,2290,1376],{"class":349},[65,2292,1989],{"class":82},[65,2294,1623],{"class":349},[65,2296,2297,2299],{"class":67,"line":816},[65,2298,1329],{"class":349},[65,2300,101],{"class":86},[65,2302,2303],{"class":67,"line":822},[65,2304,153],{"emptyLinePlaceholder":152},[65,2306,2307,2309,2311,2313,2315,2317,2319,2321,2323],{"class":67,"line":1338},[65,2308,1530],{"class":90},[65,2310,1533],{"class":349},[65,2312,1645],{"class":82},[65,2314,110],{"class":86},[65,2316,1650],{"class":82},[65,2318,1653],{"class":86},[65,2320,1656],{"class":1092},[65,2322,1539],{"class":349},[65,2324,1542],{"class":86},[65,2326,2327,2329,2332],{"class":67,"line":1344},[65,2328,1548],{"class":90},[65,2330,2331],{"class":2101}," false",[65,2333,101],{"class":86},[65,2335,2336],{"class":67,"line":1360},[65,2337,651],{"class":86},[65,2339,2340],{"class":67,"line":1373},[65,2341,153],{"emptyLinePlaceholder":152},[65,2343,2344,2346,2348,2350,2352,2354,2356,2358],{"class":67,"line":1418},[65,2345,1046],{"class":78},[65,2347,2083],{"class":82},[65,2349,1052],{"class":86},[65,2351,1587],{"class":82},[65,2353,1692],{"class":349},[65,2355,1695],{"class":1092},[65,2357,583],{"class":349},[65,2359,101],{"class":86},[65,2361,2362],{"class":67,"line":1425},[65,2363,1120],{"class":349},[65,2365,2366],{"class":67,"line":1430},[65,2367,2368],{"class":71},"    \u002F\u002F Controleer TOTP code\n",[65,2370,2371,2373,2375,2378,2380,2382,2384,2386,2388,2390,2392],{"class":67,"line":1440},[65,2372,1530],{"class":90},[65,2374,1533],{"class":349},[65,2376,2377],{"class":82},"twoFactorAuth",[65,2379,110],{"class":86},[65,2381,2116],{"class":82},[65,2383,1653],{"class":86},[65,2385,492],{"class":86},[65,2387,1877],{"class":122},[65,2389,184],{"class":86},[65,2391,1539],{"class":349},[65,2393,1542],{"class":86},[65,2395,2396,2398,2400,2402,2404,2407,2409,2411,2413,2415,2417,2420,2422],{"class":67,"line":1445},[65,2397,1548],{"class":90},[65,2399,1259],{"class":86},[65,2401,1877],{"class":82},[65,2403,110],{"class":86},[65,2405,2406],{"class":94},"verify",[65,2408,116],{"class":349},[65,2410,62],{"class":82},[65,2412,192],{"class":86},[65,2414,2083],{"class":82},[65,2416,110],{"class":86},[65,2418,2419],{"class":82},"secret",[65,2421,140],{"class":349},[65,2423,101],{"class":86},[65,2425,2426],{"class":67,"line":1450},[65,2427,651],{"class":86},[65,2429,2430],{"class":67,"line":1484},[65,2431,153],{"emptyLinePlaceholder":152},[65,2433,2434],{"class":67,"line":1490},[65,2435,2436],{"class":71},"    \u002F\u002F Controleer backup code\n",[65,2438,2439,2441,2443,2445,2447,2449,2451,2453,2455,2457,2460,2462],{"class":67,"line":1527},[65,2440,1046],{"class":78},[65,2442,2058],{"class":82},[65,2444,1052],{"class":86},[65,2446,1399],{"class":82},[65,2448,110],{"class":86},[65,2450,1555],{"class":94},[65,2452,116],{"class":349},[65,2454,2377],{"class":82},[65,2456,110],{"class":86},[65,2458,2459],{"class":82},"backup_codes",[65,2461,140],{"class":349},[65,2463,101],{"class":86},[65,2465,2466,2468,2470,2472,2474,2477,2479,2481,2484],{"class":67,"line":1545},[65,2467,1530],{"class":90},[65,2469,1533],{"class":349},[65,2471,2190],{"class":82},[65,2473,110],{"class":86},[65,2475,2476],{"class":94},"includes",[65,2478,116],{"class":349},[65,2480,62],{"class":82},[65,2482,2483],{"class":349},")) ",[65,2485,1542],{"class":86},[65,2487,2488],{"class":67,"line":1566},[65,2489,2490],{"class":71},"      \u002F\u002F Verwijder gebruikte backup code\n",[65,2492,2493,2496,2499,2501,2503,2505,2508,2510,2513,2516,2519,2522,2524,2526],{"class":67,"line":1571},[65,2494,2495],{"class":78},"      const",[65,2497,2498],{"class":82}," updatedCodes",[65,2500,1052],{"class":86},[65,2502,2058],{"class":82},[65,2504,110],{"class":86},[65,2506,2507],{"class":94},"filter",[65,2509,116],{"class":349},[65,2511,2512],{"class":1009},"c",[65,2514,2515],{"class":78}," =>",[65,2517,2518],{"class":82}," c",[65,2520,2521],{"class":86}," !==",[65,2523,2238],{"class":82},[65,2525,140],{"class":349},[65,2527,101],{"class":86},[65,2529,2530,2533,2535,2537,2539,2541],{"class":67,"line":1576},[65,2531,2532],{"class":90},"      await",[65,2534,1259],{"class":86},[65,2536,1351],{"class":82},[65,2538,110],{"class":86},[65,2540,179],{"class":94},[65,2542,1270],{"class":349},[65,2544,2545,2548,2551,2553],{"class":67,"line":1582},[65,2546,2547],{"class":86},"        '",[65,2549,2550],{"class":122},"UPDATE two_factor_auth SET backup_codes = ? WHERE user_id = ?",[65,2552,184],{"class":86},[65,2554,500],{"class":86},[65,2556,2557,2560,2563,2565,2567,2569,2572,2574,2576,2579],{"class":67,"line":1604},[65,2558,2559],{"class":349},"        [",[65,2561,2562],{"class":82},"JSON",[65,2564,110],{"class":86},[65,2566,1316],{"class":94},[65,2568,116],{"class":349},[65,2570,2571],{"class":82},"updatedCodes",[65,2573,140],{"class":349},[65,2575,192],{"class":86},[65,2577,2578],{"class":82}," userId",[65,2580,1623],{"class":349},[65,2582,2583,2586],{"class":67,"line":1616},[65,2584,2585],{"class":349},"      )",[65,2587,101],{"class":86},[65,2589,2590,2592,2594],{"class":67,"line":1626},[65,2591,1548],{"class":90},[65,2593,2102],{"class":2101},[65,2595,101],{"class":86},[65,2597,2598],{"class":67,"line":1633},[65,2599,651],{"class":86},[65,2601,2602],{"class":67,"line":1638},[65,2603,153],{"emptyLinePlaceholder":152},[65,2605,2606,2608,2610],{"class":67,"line":1663},[65,2607,1433],{"class":90},[65,2609,2331],{"class":2101},[65,2611,101],{"class":86},[65,2613,2614],{"class":67,"line":1671},[65,2615,819],{"class":86},[65,2617,2618],{"class":67,"line":1676},[65,2619,450],{"class":86},[24,2621,2622],{},[30,2623,831],{},[34,2625,2626,2629,2632,2635],{},[37,2627,2628],{},"Meerdere 2FA methoden ondersteunen",[37,2630,2631],{},"Backup codes voor noodgevallen",[37,2633,2634],{},"TOTP voor authenticator apps",[37,2636,2637],{},"SMS en email voor alternatieve methoden",[24,2639,2640,2642],{},[30,2641,1824],{}," Security verbeterde zonder performance impact",[19,2644,2646],{"id":2645},"de-game-changer-performance-optimalisatie","De Game Changer: Performance Optimalisatie",[316,2648,2650],{"id":2649},"het-probleem-authenticatie-performance-bottlenecks","Het Probleem: Authenticatie Performance Bottlenecks",[24,2652,2653],{},"Zelfs met betere implementatie waren er nog performance bottlenecks:",[55,2655,2657],{"className":57,"code":2656,"language":59,"meta":60,"style":60},"\u002F\u002F Probleem: Meerdere database queries per authenticatie\nasync function authenticateUser(email: string, password: string) {\n  const user = await db.query('SELECT * FROM users WHERE email = ?', [email]);\n  const permissions = await db.query('SELECT * FROM permissions WHERE user_id = ?', [user.id]);\n  const sessions = await db.query('SELECT * FROM sessions WHERE user_id = ?', [user.id]);\n  const twoFactor = await db.query('SELECT * FROM two_factor_auth WHERE user_id = ?', [user.id]);\n  \u002F\u002F 4 database queries per authenticatie!\n}\n",[62,2658,2659,2664,2696,2732,2771,2810,2849,2854],{"__ignoreMap":60},[65,2660,2661],{"class":67,"line":68},[65,2662,2663],{"class":71},"\u002F\u002F Probleem: Meerdere database queries per authenticatie\n",[65,2665,2666,2669,2672,2675,2677,2679,2681,2683,2685,2688,2690,2692,2694],{"class":67,"line":75},[65,2667,2668],{"class":78},"async",[65,2670,2671],{"class":78}," function",[65,2673,2674],{"class":94}," authenticateUser",[65,2676,116],{"class":86},[65,2678,569],{"class":1009},[65,2680,353],{"class":86},[65,2682,356],{"class":340},[65,2684,192],{"class":86},[65,2686,2687],{"class":1009}," password",[65,2689,353],{"class":86},[65,2691,356],{"class":340},[65,2693,140],{"class":86},[65,2695,344],{"class":86},[65,2697,2698,2701,2703,2705,2707,2709,2711,2713,2715,2717,2719,2721,2723,2725,2727,2730],{"class":67,"line":104},[65,2699,2700],{"class":78},"  const",[65,2702,1156],{"class":82},[65,2704,1052],{"class":86},[65,2706,91],{"class":90},[65,2708,174],{"class":82},[65,2710,110],{"class":86},[65,2712,179],{"class":94},[65,2714,116],{"class":349},[65,2716,184],{"class":86},[65,2718,187],{"class":122},[65,2720,184],{"class":86},[65,2722,192],{"class":86},[65,2724,555],{"class":349},[65,2726,569],{"class":82},[65,2728,2729],{"class":349},"])",[65,2731,101],{"class":86},[65,2733,2734,2736,2739,2741,2743,2745,2747,2749,2751,2753,2755,2757,2759,2761,2763,2765,2767,2769],{"class":67,"line":149},[65,2735,2700],{"class":78},[65,2737,2738],{"class":82}," permissions",[65,2740,1052],{"class":86},[65,2742,91],{"class":90},[65,2744,174],{"class":82},[65,2746,110],{"class":86},[65,2748,179],{"class":94},[65,2750,116],{"class":349},[65,2752,184],{"class":86},[65,2754,222],{"class":122},[65,2756,184],{"class":86},[65,2758,192],{"class":86},[65,2760,555],{"class":349},[65,2762,1010],{"class":82},[65,2764,110],{"class":86},[65,2766,1161],{"class":82},[65,2768,2729],{"class":349},[65,2770,101],{"class":86},[65,2772,2773,2775,2778,2780,2782,2784,2786,2788,2790,2792,2794,2796,2798,2800,2802,2804,2806,2808],{"class":67,"line":156},[65,2774,2700],{"class":78},[65,2776,2777],{"class":82}," sessions",[65,2779,1052],{"class":86},[65,2781,91],{"class":90},[65,2783,174],{"class":82},[65,2785,110],{"class":86},[65,2787,179],{"class":94},[65,2789,116],{"class":349},[65,2791,184],{"class":86},[65,2793,261],{"class":122},[65,2795,184],{"class":86},[65,2797,192],{"class":86},[65,2799,555],{"class":349},[65,2801,1010],{"class":82},[65,2803,110],{"class":86},[65,2805,1161],{"class":82},[65,2807,2729],{"class":349},[65,2809,101],{"class":86},[65,2811,2812,2814,2817,2819,2821,2823,2825,2827,2829,2831,2833,2835,2837,2839,2841,2843,2845,2847],{"class":67,"line":162},[65,2813,2700],{"class":78},[65,2815,2816],{"class":82}," twoFactor",[65,2818,1052],{"class":86},[65,2820,91],{"class":90},[65,2822,174],{"class":82},[65,2824,110],{"class":86},[65,2826,179],{"class":94},[65,2828,116],{"class":349},[65,2830,184],{"class":86},[65,2832,2282],{"class":122},[65,2834,184],{"class":86},[65,2836,192],{"class":86},[65,2838,555],{"class":349},[65,2840,1010],{"class":82},[65,2842,110],{"class":86},[65,2844,1161],{"class":82},[65,2846,2729],{"class":349},[65,2848,101],{"class":86},[65,2850,2851],{"class":67,"line":200},[65,2852,2853],{"class":71},"  \u002F\u002F 4 database queries per authenticatie!\n",[65,2855,2856],{"class":67,"line":239},[65,2857,450],{"class":86},[316,2859,2861],{"id":2860},"de-oplossing-geoptimaliseerde-authenticatie-flow","De Oplossing: Geoptimaliseerde Authenticatie Flow",[24,2863,2864],{},"We implementeerden een geoptimaliseerde authenticatie flow:",[55,2866,2868],{"className":57,"code":2867,"language":59,"meta":60,"style":60},"\u002F\u002F Oplossing: Geoptimaliseerde authenticatie flow\nclass OptimizedAuthService {\n  private redis: Redis;\n  private db: Database;\n\n  async authenticateUser(email: string, password: string): Promise\u003CAuthResult> {\n    \u002F\u002F Cache gebruikersdata voor snelle toegang\n    const cacheKey = `user:${email}`;\n    let user = await this.redis.get(cacheKey);\n    \n    if (!user) {\n      \u002F\u002F Haal gebruiker op uit database\n      const result = await this.db.query(\n        'SELECT u.*, p.permissions, tfa.enabled as two_factor_enabled FROM users u ' +\n        'LEFT JOIN permissions p ON u.id = p.user_id ' +\n        'LEFT JOIN two_factor_auth tfa ON u.id = tfa.user_id ' +\n        'WHERE u.email = ?',\n        [email]\n      );\n      \n      if (result.length === 0) {\n        throw new Error('Gebruiker niet gevonden');\n      }\n      \n      user = result[0];\n      \n      \u002F\u002F Cache voor 5 minuten\n      await this.redis.setex(cacheKey, 300, JSON.stringify(user));\n    } else {\n      user = JSON.parse(user);\n    }\n\n    \u002F\u002F Verifieer wachtwoord\n    const isValidPassword = await bcrypt.compare(password, user.password_hash);\n    if (!isValidPassword) {\n      throw new Error('Ongeldig wachtwoord');\n    }\n\n    \u002F\u002F Genereer JWT token\n    const token = jwt.sign(\n      { \n        userId: user.id, \n        email: user.email,\n        permissions: user.permissions \n      },\n      process.env.JWT_SECRET,\n      { expiresIn: '24h' }\n    );\n\n    return {\n      user: {\n        id: user.id,\n        email: user.email,\n        name: user.name,\n        permissions: user.permissions\n      },\n      token,\n      twoFactorRequired: user.two_factor_enabled\n    };\n  }\n\n  async refreshToken(refreshToken: string): Promise\u003Cstring> {\n    \u002F\u002F Valideer refresh token\n    const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);\n    \n    \u002F\u002F Genereer nieuw access token\n    const newToken = jwt.sign(\n      { userId: decoded.userId, email: decoded.email },\n      process.env.JWT_SECRET,\n      { expiresIn: '24h' }\n    );\n\n    return newToken;\n  }\n}\n",[62,2869,2870,2875,2884,2896,2908,2912,2947,2952,2975,3003,3007,3022,3027,3047,3059,3070,3081,3092,3100,3106,3111,3132,3155,3159,3163,3180,3184,3189,3227,3237,3257,3261,3265,3270,3307,3322,3344,3348,3352,3357,3376,3384,3401,3416,3432,3437,3453,3472,3478,3482,3488,3496,3511,3525,3541,3554,3558,3564,3578,3582,3586,3590,3619,3624,3660,3664,3669,3686,3715,3729,3745,3751,3755,3763,3767],{"__ignoreMap":60},[65,2871,2872],{"class":67,"line":68},[65,2873,2874],{"class":71},"\u002F\u002F Oplossing: Geoptimaliseerde authenticatie flow\n",[65,2876,2877,2879,2882],{"class":67,"line":75},[65,2878,959],{"class":78},[65,2880,2881],{"class":340}," OptimizedAuthService",[65,2883,344],{"class":86},[65,2885,2886,2888,2890,2892,2894],{"class":67,"line":104},[65,2887,969],{"class":78},[65,2889,972],{"class":349},[65,2891,353],{"class":86},[65,2893,977],{"class":340},[65,2895,101],{"class":86},[65,2897,2898,2900,2902,2904,2906],{"class":67,"line":149},[65,2899,969],{"class":78},[65,2901,174],{"class":349},[65,2903,353],{"class":86},[65,2905,990],{"class":340},[65,2907,101],{"class":86},[65,2909,2910],{"class":67,"line":156},[65,2911,153],{"emptyLinePlaceholder":152},[65,2913,2914,2916,2918,2920,2922,2924,2926,2928,2930,2932,2934,2936,2938,2940,2943,2945],{"class":67,"line":162},[65,2915,1001],{"class":78},[65,2917,2674],{"class":349},[65,2919,116],{"class":86},[65,2921,569],{"class":1009},[65,2923,353],{"class":86},[65,2925,356],{"class":340},[65,2927,192],{"class":86},[65,2929,2687],{"class":1009},[65,2931,353],{"class":86},[65,2933,356],{"class":340},[65,2935,1027],{"class":86},[65,2937,1030],{"class":340},[65,2939,1033],{"class":86},[65,2941,2942],{"class":340},"AuthResult",[65,2944,1039],{"class":86},[65,2946,344],{"class":86},[65,2948,2949],{"class":67,"line":200},[65,2950,2951],{"class":71},"    \u002F\u002F Cache gebruikersdata voor snelle toegang\n",[65,2953,2954,2956,2959,2961,2964,2967,2969,2971,2973],{"class":67,"line":239},[65,2955,1046],{"class":78},[65,2957,2958],{"class":82}," cacheKey",[65,2960,1052],{"class":86},[65,2962,2963],{"class":86}," `",[65,2965,2966],{"class":122},"user:",[65,2968,126],{"class":86},[65,2970,569],{"class":82},[65,2972,1286],{"class":86},[65,2974,101],{"class":86},[65,2976,2977,2980,2982,2984,2986,2988,2990,2992,2994,2996,2999,3001],{"class":67,"line":417},[65,2978,2979],{"class":78},"    let",[65,2981,1156],{"class":82},[65,2983,1052],{"class":86},[65,2985,91],{"class":90},[65,2987,1259],{"class":86},[65,2989,1262],{"class":82},[65,2991,110],{"class":86},[65,2993,1508],{"class":94},[65,2995,116],{"class":349},[65,2997,2998],{"class":82},"cacheKey",[65,3000,140],{"class":349},[65,3002,101],{"class":86},[65,3004,3005],{"class":67,"line":429},[65,3006,1120],{"class":349},[65,3008,3009,3011,3013,3016,3018,3020],{"class":67,"line":441},[65,3010,1530],{"class":90},[65,3012,1533],{"class":349},[65,3014,3015],{"class":86},"!",[65,3017,1010],{"class":82},[65,3019,1539],{"class":349},[65,3021,1542],{"class":86},[65,3023,3024],{"class":67,"line":447},[65,3025,3026],{"class":71},"      \u002F\u002F Haal gebruiker op uit database\n",[65,3028,3029,3031,3033,3035,3037,3039,3041,3043,3045],{"class":67,"line":453},[65,3030,2495],{"class":78},[65,3032,1587],{"class":82},[65,3034,1052],{"class":86},[65,3036,91],{"class":90},[65,3038,1259],{"class":86},[65,3040,1351],{"class":82},[65,3042,110],{"class":86},[65,3044,179],{"class":94},[65,3046,1270],{"class":349},[65,3048,3049,3051,3054,3056],{"class":67,"line":458},[65,3050,2547],{"class":86},[65,3052,3053],{"class":122},"SELECT u.*, p.permissions, tfa.enabled as two_factor_enabled FROM users u ",[65,3055,184],{"class":86},[65,3057,3058],{"class":86}," +\n",[65,3060,3061,3063,3066,3068],{"class":67,"line":478},[65,3062,2547],{"class":86},[65,3064,3065],{"class":122},"LEFT JOIN permissions p ON u.id = p.user_id ",[65,3067,184],{"class":86},[65,3069,3058],{"class":86},[65,3071,3072,3074,3077,3079],{"class":67,"line":484},[65,3073,2547],{"class":86},[65,3075,3076],{"class":122},"LEFT JOIN two_factor_auth tfa ON u.id = tfa.user_id ",[65,3078,184],{"class":86},[65,3080,3058],{"class":86},[65,3082,3083,3085,3088,3090],{"class":67,"line":503},[65,3084,2547],{"class":86},[65,3086,3087],{"class":122},"WHERE u.email = ?",[65,3089,184],{"class":86},[65,3091,500],{"class":86},[65,3093,3094,3096,3098],{"class":67,"line":526},[65,3095,2559],{"class":349},[65,3097,569],{"class":82},[65,3099,1623],{"class":349},[65,3101,3102,3104],{"class":67,"line":547},[65,3103,2585],{"class":349},[65,3105,101],{"class":86},[65,3107,3108],{"class":67,"line":588},[65,3109,3110],{"class":349},"      \n",[65,3112,3113,3116,3118,3120,3122,3124,3126,3128,3130],{"class":67,"line":598},[65,3114,3115],{"class":90},"      if",[65,3117,1533],{"class":349},[65,3119,1645],{"class":82},[65,3121,110],{"class":86},[65,3123,1650],{"class":82},[65,3125,1653],{"class":86},[65,3127,1656],{"class":1092},[65,3129,1539],{"class":349},[65,3131,1542],{"class":86},[65,3133,3134,3137,3139,3142,3144,3146,3149,3151,3153],{"class":67,"line":615},[65,3135,3136],{"class":90},"        throw",[65,3138,1071],{"class":86},[65,3140,3141],{"class":94}," Error",[65,3143,116],{"class":349},[65,3145,184],{"class":86},[65,3147,3148],{"class":122},"Gebruiker niet gevonden",[65,3150,184],{"class":86},[65,3152,140],{"class":349},[65,3154,101],{"class":86},[65,3156,3157],{"class":67,"line":632},[65,3158,1237],{"class":86},[65,3160,3161],{"class":67,"line":648},[65,3162,3110],{"class":349},[65,3164,3165,3168,3170,3172,3174,3176,3178],{"class":67,"line":654},[65,3166,3167],{"class":82},"      user",[65,3169,1052],{"class":86},[65,3171,1587],{"class":82},[65,3173,1692],{"class":349},[65,3175,1695],{"class":1092},[65,3177,583],{"class":349},[65,3179,101],{"class":86},[65,3181,3182],{"class":67,"line":660},[65,3183,3110],{"class":349},[65,3185,3186],{"class":67,"line":665},[65,3187,3188],{"class":71},"      \u002F\u002F Cache voor 5 minuten\n",[65,3190,3191,3193,3195,3197,3199,3201,3203,3205,3207,3210,3212,3214,3216,3218,3220,3222,3225],{"class":67,"line":681},[65,3192,2532],{"class":90},[65,3194,1259],{"class":86},[65,3196,1262],{"class":82},[65,3198,110],{"class":86},[65,3200,1267],{"class":94},[65,3202,116],{"class":349},[65,3204,2998],{"class":82},[65,3206,192],{"class":86},[65,3208,3209],{"class":1092}," 300",[65,3211,192],{"class":86},[65,3213,1399],{"class":82},[65,3215,110],{"class":86},[65,3217,1316],{"class":94},[65,3219,116],{"class":349},[65,3221,1010],{"class":82},[65,3223,3224],{"class":349},"))",[65,3226,101],{"class":86},[65,3228,3229,3232,3235],{"class":67,"line":701},[65,3230,3231],{"class":86},"    }",[65,3233,3234],{"class":90}," else",[65,3236,344],{"class":86},[65,3238,3239,3241,3243,3245,3247,3249,3251,3253,3255],{"class":67,"line":721},[65,3240,3167],{"class":82},[65,3242,1052],{"class":86},[65,3244,1399],{"class":82},[65,3246,110],{"class":86},[65,3248,1555],{"class":94},[65,3250,116],{"class":349},[65,3252,1010],{"class":82},[65,3254,140],{"class":349},[65,3256,101],{"class":86},[65,3258,3259],{"class":67,"line":756},[65,3260,651],{"class":86},[65,3262,3263],{"class":67,"line":765},[65,3264,153],{"emptyLinePlaceholder":152},[65,3266,3267],{"class":67,"line":781},[65,3268,3269],{"class":71},"    \u002F\u002F Verifieer wachtwoord\n",[65,3271,3272,3274,3277,3279,3281,3284,3286,3289,3291,3294,3296,3298,3300,3303,3305],{"class":67,"line":797},[65,3273,1046],{"class":78},[65,3275,3276],{"class":82}," isValidPassword",[65,3278,1052],{"class":86},[65,3280,91],{"class":90},[65,3282,3283],{"class":82}," bcrypt",[65,3285,110],{"class":86},[65,3287,3288],{"class":94},"compare",[65,3290,116],{"class":349},[65,3292,3293],{"class":82},"password",[65,3295,192],{"class":86},[65,3297,1156],{"class":82},[65,3299,110],{"class":86},[65,3301,3302],{"class":82},"password_hash",[65,3304,140],{"class":349},[65,3306,101],{"class":86},[65,3308,3309,3311,3313,3315,3318,3320],{"class":67,"line":811},[65,3310,1530],{"class":90},[65,3312,1533],{"class":349},[65,3314,3015],{"class":86},[65,3316,3317],{"class":82},"isValidPassword",[65,3319,1539],{"class":349},[65,3321,1542],{"class":86},[65,3323,3324,3327,3329,3331,3333,3335,3338,3340,3342],{"class":67,"line":816},[65,3325,3326],{"class":90},"      throw",[65,3328,1071],{"class":86},[65,3330,3141],{"class":94},[65,3332,116],{"class":349},[65,3334,184],{"class":86},[65,3336,3337],{"class":122},"Ongeldig wachtwoord",[65,3339,184],{"class":86},[65,3341,140],{"class":349},[65,3343,101],{"class":86},[65,3345,3346],{"class":67,"line":822},[65,3347,651],{"class":86},[65,3349,3350],{"class":67,"line":1338},[65,3351,153],{"emptyLinePlaceholder":152},[65,3353,3354],{"class":67,"line":1344},[65,3355,3356],{"class":71},"    \u002F\u002F Genereer JWT token\n",[65,3358,3359,3361,3364,3366,3369,3371,3374],{"class":67,"line":1360},[65,3360,1046],{"class":78},[65,3362,3363],{"class":82}," token",[65,3365,1052],{"class":86},[65,3367,3368],{"class":82}," jwt",[65,3370,110],{"class":86},[65,3372,3373],{"class":94},"sign",[65,3375,1270],{"class":349},[65,3377,3378,3381],{"class":67,"line":1373},[65,3379,3380],{"class":86},"      {",[65,3382,3383],{"class":349}," \n",[65,3385,3386,3389,3391,3393,3395,3397,3399],{"class":67,"line":1418},[65,3387,3388],{"class":349},"        userId",[65,3390,353],{"class":86},[65,3392,1156],{"class":82},[65,3394,110],{"class":86},[65,3396,1161],{"class":82},[65,3398,192],{"class":86},[65,3400,3383],{"class":349},[65,3402,3403,3406,3408,3410,3412,3414],{"class":67,"line":1425},[65,3404,3405],{"class":349},"        email",[65,3407,353],{"class":86},[65,3409,1156],{"class":82},[65,3411,110],{"class":86},[65,3413,569],{"class":82},[65,3415,500],{"class":86},[65,3417,3418,3421,3423,3425,3427,3430],{"class":67,"line":1430},[65,3419,3420],{"class":349},"        permissions",[65,3422,353],{"class":86},[65,3424,1156],{"class":82},[65,3426,110],{"class":86},[65,3428,3429],{"class":82},"permissions",[65,3431,3383],{"class":349},[65,3433,3434],{"class":67,"line":1440},[65,3435,3436],{"class":86},"      },\n",[65,3438,3439,3442,3444,3446,3448,3451],{"class":67,"line":1445},[65,3440,3441],{"class":82},"      process",[65,3443,110],{"class":86},[65,3445,516],{"class":82},[65,3447,110],{"class":86},[65,3449,3450],{"class":82},"JWT_SECRET",[65,3452,500],{"class":86},[65,3454,3455,3457,3460,3462,3464,3467,3469],{"class":67,"line":1450},[65,3456,3380],{"class":86},[65,3458,3459],{"class":349}," expiresIn",[65,3461,353],{"class":86},[65,3463,492],{"class":86},[65,3465,3466],{"class":122},"24h",[65,3468,184],{"class":86},[65,3470,3471],{"class":86}," }\n",[65,3473,3474,3476],{"class":67,"line":1484},[65,3475,1329],{"class":349},[65,3477,101],{"class":86},[65,3479,3480],{"class":67,"line":1490},[65,3481,153],{"emptyLinePlaceholder":152},[65,3483,3484,3486],{"class":67,"line":1527},[65,3485,1433],{"class":90},[65,3487,344],{"class":86},[65,3489,3490,3492,3494],{"class":67,"line":1545},[65,3491,3167],{"class":349},[65,3493,353],{"class":86},[65,3495,344],{"class":86},[65,3497,3498,3501,3503,3505,3507,3509],{"class":67,"line":1566},[65,3499,3500],{"class":349},"        id",[65,3502,353],{"class":86},[65,3504,1156],{"class":82},[65,3506,110],{"class":86},[65,3508,1161],{"class":82},[65,3510,500],{"class":86},[65,3512,3513,3515,3517,3519,3521,3523],{"class":67,"line":1571},[65,3514,3405],{"class":349},[65,3516,353],{"class":86},[65,3518,1156],{"class":82},[65,3520,110],{"class":86},[65,3522,569],{"class":82},[65,3524,500],{"class":86},[65,3526,3527,3530,3532,3534,3536,3539],{"class":67,"line":1576},[65,3528,3529],{"class":349},"        name",[65,3531,353],{"class":86},[65,3533,1156],{"class":82},[65,3535,110],{"class":86},[65,3537,3538],{"class":82},"name",[65,3540,500],{"class":86},[65,3542,3543,3545,3547,3549,3551],{"class":67,"line":1582},[65,3544,3420],{"class":349},[65,3546,353],{"class":86},[65,3548,1156],{"class":82},[65,3550,110],{"class":86},[65,3552,3553],{"class":82},"permissions\n",[65,3555,3556],{"class":67,"line":1604},[65,3557,3436],{"class":86},[65,3559,3560,3562],{"class":67,"line":1616},[65,3561,618],{"class":82},[65,3563,500],{"class":86},[65,3565,3566,3569,3571,3573,3575],{"class":67,"line":1626},[65,3567,3568],{"class":349},"      twoFactorRequired",[65,3570,353],{"class":86},[65,3572,1156],{"class":82},[65,3574,110],{"class":86},[65,3576,3577],{"class":82},"two_factor_enabled\n",[65,3579,3580],{"class":67,"line":1633},[65,3581,1242],{"class":86},[65,3583,3584],{"class":67,"line":1638},[65,3585,819],{"class":86},[65,3587,3588],{"class":67,"line":1663},[65,3589,153],{"emptyLinePlaceholder":152},[65,3591,3592,3594,3597,3599,3602,3604,3606,3608,3610,3612,3615,3617],{"class":67,"line":1671},[65,3593,1001],{"class":78},[65,3595,3596],{"class":349}," refreshToken",[65,3598,116],{"class":86},[65,3600,3601],{"class":1009},"refreshToken",[65,3603,353],{"class":86},[65,3605,356],{"class":340},[65,3607,1027],{"class":86},[65,3609,1030],{"class":340},[65,3611,1033],{"class":86},[65,3613,3614],{"class":340},"string",[65,3616,1039],{"class":86},[65,3618,344],{"class":86},[65,3620,3621],{"class":67,"line":1676},[65,3622,3623],{"class":71},"    \u002F\u002F Valideer refresh token\n",[65,3625,3626,3628,3631,3633,3635,3637,3639,3641,3643,3645,3647,3649,3651,3653,3656,3658],{"class":67,"line":1681},[65,3627,1046],{"class":78},[65,3629,3630],{"class":82}," decoded",[65,3632,1052],{"class":86},[65,3634,3368],{"class":82},[65,3636,110],{"class":86},[65,3638,2406],{"class":94},[65,3640,116],{"class":349},[65,3642,3601],{"class":82},[65,3644,192],{"class":86},[65,3646,511],{"class":82},[65,3648,110],{"class":86},[65,3650,516],{"class":82},[65,3652,110],{"class":86},[65,3654,3655],{"class":82},"JWT_REFRESH_SECRET",[65,3657,140],{"class":349},[65,3659,101],{"class":86},[65,3661,3662],{"class":67,"line":1702},[65,3663,1120],{"class":349},[65,3665,3666],{"class":67,"line":1707},[65,3667,3668],{"class":71},"    \u002F\u002F Genereer nieuw access token\n",[65,3670,3671,3673,3676,3678,3680,3682,3684],{"class":67,"line":1713},[65,3672,1046],{"class":78},[65,3674,3675],{"class":82}," newToken",[65,3677,1052],{"class":86},[65,3679,3368],{"class":82},[65,3681,110],{"class":86},[65,3683,3373],{"class":94},[65,3685,1270],{"class":349},[65,3687,3688,3690,3692,3694,3696,3698,3700,3702,3704,3706,3708,3710,3712],{"class":67,"line":1728},[65,3689,3380],{"class":86},[65,3691,2578],{"class":349},[65,3693,353],{"class":86},[65,3695,3630],{"class":82},[65,3697,110],{"class":86},[65,3699,1989],{"class":82},[65,3701,192],{"class":86},[65,3703,1966],{"class":349},[65,3705,353],{"class":86},[65,3707,3630],{"class":82},[65,3709,110],{"class":86},[65,3711,569],{"class":82},[65,3713,3714],{"class":86}," },\n",[65,3716,3717,3719,3721,3723,3725,3727],{"class":67,"line":1743},[65,3718,3441],{"class":82},[65,3720,110],{"class":86},[65,3722,516],{"class":82},[65,3724,110],{"class":86},[65,3726,3450],{"class":82},[65,3728,500],{"class":86},[65,3730,3731,3733,3735,3737,3739,3741,3743],{"class":67,"line":1758},[65,3732,3380],{"class":86},[65,3734,3459],{"class":349},[65,3736,353],{"class":86},[65,3738,492],{"class":86},[65,3740,3466],{"class":122},[65,3742,184],{"class":86},[65,3744,3471],{"class":86},[65,3746,3747,3749],{"class":67,"line":1773},[65,3748,1329],{"class":349},[65,3750,101],{"class":86},[65,3752,3753],{"class":67,"line":1780},[65,3754,153],{"emptyLinePlaceholder":152},[65,3756,3757,3759,3761],{"class":67,"line":1785},[65,3758,1433],{"class":90},[65,3760,3675],{"class":82},[65,3762,101],{"class":86},[65,3764,3765],{"class":67,"line":1794},[65,3766,819],{"class":86},[65,3768,3769],{"class":67,"line":1799},[65,3770,450],{"class":86},[24,3772,3773],{},[30,3774,831],{},[34,3776,3777,3780,3783,3786],{},[37,3778,3779],{},"Single database query met JOINs",[37,3781,3782],{},"Redis caching voor gebruikersdata",[37,3784,3785],{},"JWT tokens voor stateless authenticatie",[37,3787,3788],{},"Refresh tokens voor lange sessies",[24,3790,3791,3793],{},[30,3792,1824],{}," Authenticatie tijd verbeterde naar 200ms (15x verbetering)",[19,3795,3797],{"id":3796},"de-finale-optimalisatie-security-monitoring","De Finale Optimalisatie: Security Monitoring",[316,3799,3801],{"id":3800},"het-probleem-security-threats-detection","Het Probleem: Security Threats Detection",[24,3803,3804],{},"Zelfs met geoptimaliseerde authenticatie waren er security threats:",[55,3806,3808],{"className":57,"code":3807,"language":59,"meta":60,"style":60},"\u002F\u002F Probleem: Geen monitoring van security threats\ninterface SecurityThreat {\n  type: 'brute_force' | 'suspicious_login' | 'account_takeover';\n  userId: string;\n  ip: string;\n  timestamp: Date;\n  details: any;\n}\n",[62,3809,3810,3815,3824,3858,3868,3879,3890,3902],{"__ignoreMap":60},[65,3811,3812],{"class":67,"line":68},[65,3813,3814],{"class":71},"\u002F\u002F Probleem: Geen monitoring van security threats\n",[65,3816,3817,3819,3822],{"class":67,"line":75},[65,3818,337],{"class":78},[65,3820,3821],{"class":340}," SecurityThreat",[65,3823,344],{"class":86},[65,3825,3826,3829,3831,3833,3836,3838,3840,3842,3845,3847,3849,3851,3854,3856],{"class":67,"line":104},[65,3827,3828],{"class":349},"  type",[65,3830,353],{"class":86},[65,3832,492],{"class":86},[65,3834,3835],{"class":122},"brute_force",[65,3837,184],{"class":86},[65,3839,1474],{"class":86},[65,3841,492],{"class":86},[65,3843,3844],{"class":122},"suspicious_login",[65,3846,184],{"class":86},[65,3848,1474],{"class":86},[65,3850,492],{"class":86},[65,3852,3853],{"class":122},"account_takeover",[65,3855,184],{"class":86},[65,3857,101],{"class":86},[65,3859,3860,3862,3864,3866],{"class":67,"line":149},[65,3861,893],{"class":349},[65,3863,353],{"class":86},[65,3865,356],{"class":340},[65,3867,101],{"class":86},[65,3869,3870,3873,3875,3877],{"class":67,"line":156},[65,3871,3872],{"class":349},"  ip",[65,3874,353],{"class":86},[65,3876,356],{"class":340},[65,3878,101],{"class":86},[65,3880,3881,3884,3886,3888],{"class":67,"line":162},[65,3882,3883],{"class":349},"  timestamp",[65,3885,353],{"class":86},[65,3887,920],{"class":340},[65,3889,101],{"class":86},[65,3891,3892,3895,3897,3900],{"class":67,"line":200},[65,3893,3894],{"class":349},"  details",[65,3896,353],{"class":86},[65,3898,3899],{"class":340}," any",[65,3901,101],{"class":86},[65,3903,3904],{"class":67,"line":239},[65,3905,450],{"class":86},[316,3907,3909],{"id":3908},"de-oplossing-geautomatiseerde-security-monitoring","De Oplossing: Geautomatiseerde Security Monitoring",[24,3911,3912],{},"We implementeerden geautomatiseerde security monitoring:",[55,3914,3916],{"className":57,"code":3915,"language":59,"meta":60,"style":60},"\u002F\u002F Security monitoring systeem\nclass SecurityMonitor {\n  private redis: Redis;\n  private db: Database;\n\n  async trackLoginAttempt(email: string, ip: string, success: boolean): Promise\u003Cvoid> {\n    const key = `login_attempts:${ip}`;\n    const attempts = await this.redis.get(key);\n    \n    if (attempts) {\n      const count = parseInt(attempts);\n      if (count >= 5) {\n        \u002F\u002F Brute force detectie\n        await this.handleBruteForce(email, ip);\n      }\n    } else {\n      await this.redis.setex(key, 300, '1'); \u002F\u002F 5 minuten TTL\n    }\n\n    \u002F\u002F Log login attempt\n    await this.db.query(\n      'INSERT INTO login_attempts (email, ip, success, timestamp) VALUES (?, ?, ?, ?)',\n      [email, ip, success, new Date()]\n    );\n  }\n\n  async handleBruteForce(email: string, ip: string): Promise\u003Cvoid> {\n    \u002F\u002F Blokkeer IP tijdelijk\n    await this.redis.setex(`blocked_ip:${ip}`, 3600, '1'); \u002F\u002F 1 uur blokkering\n    \n    \u002F\u002F Notificeer beheerder\n    await this.notifyAdmin({\n      type: 'brute_force',\n      email,\n      ip,\n      timestamp: new Date()\n    });\n  }\n\n  async detectSuspiciousActivity(userId: string, activity: any): Promise\u003Cvoid> {\n    \u002F\u002F Detecteer verdachte activiteit\n    const recentLogins = await this.db.query(\n      'SELECT * FROM login_attempts WHERE user_id = ? AND timestamp > ?',\n      [userId, new Date(Date.now() - 24 * 60 * 60 * 1000)]\n    );\n\n    if (recentLogins.length > 10) {\n      \u002F\u002F Verdachte activiteit gedetecteerd\n      await this.notifyAdmin({\n        type: 'suspicious_activity',\n        userId,\n        activity,\n        timestamp: new Date()\n      });\n    }\n  }\n}\n",[62,3917,3918,3923,3932,3944,3956,3960,4006,4029,4057,4061,4074,4094,4113,4118,4140,4144,4152,4188,4192,4196,4201,4215,4226,4249,4255,4259,4263,4298,4303,4348,4352,4357,4370,4385,4392,4399,4412,4420,4424,4428,4464,4469,4490,4501,4542,4548,4552,4575,4580,4592,4608,4614,4621,4634,4643,4647,4651],{"__ignoreMap":60},[65,3919,3920],{"class":67,"line":68},[65,3921,3922],{"class":71},"\u002F\u002F Security monitoring systeem\n",[65,3924,3925,3927,3930],{"class":67,"line":75},[65,3926,959],{"class":78},[65,3928,3929],{"class":340}," SecurityMonitor",[65,3931,344],{"class":86},[65,3933,3934,3936,3938,3940,3942],{"class":67,"line":104},[65,3935,969],{"class":78},[65,3937,972],{"class":349},[65,3939,353],{"class":86},[65,3941,977],{"class":340},[65,3943,101],{"class":86},[65,3945,3946,3948,3950,3952,3954],{"class":67,"line":149},[65,3947,969],{"class":78},[65,3949,174],{"class":349},[65,3951,353],{"class":86},[65,3953,990],{"class":340},[65,3955,101],{"class":86},[65,3957,3958],{"class":67,"line":156},[65,3959,153],{"emptyLinePlaceholder":152},[65,3961,3962,3964,3967,3969,3971,3973,3975,3977,3980,3982,3984,3986,3989,3991,3993,3995,3997,3999,4002,4004],{"class":67,"line":162},[65,3963,1001],{"class":78},[65,3965,3966],{"class":349}," trackLoginAttempt",[65,3968,116],{"class":86},[65,3970,569],{"class":1009},[65,3972,353],{"class":86},[65,3974,356],{"class":340},[65,3976,192],{"class":86},[65,3978,3979],{"class":1009}," ip",[65,3981,353],{"class":86},[65,3983,356],{"class":340},[65,3985,192],{"class":86},[65,3987,3988],{"class":1009}," success",[65,3990,353],{"class":86},[65,3992,1861],{"class":340},[65,3994,1027],{"class":86},[65,3996,1030],{"class":340},[65,3998,1033],{"class":86},[65,4000,4001],{"class":340},"void",[65,4003,1039],{"class":86},[65,4005,344],{"class":86},[65,4007,4008,4010,4013,4015,4017,4020,4022,4025,4027],{"class":67,"line":200},[65,4009,1046],{"class":78},[65,4011,4012],{"class":82}," key",[65,4014,1052],{"class":86},[65,4016,2963],{"class":86},[65,4018,4019],{"class":122},"login_attempts:",[65,4021,126],{"class":86},[65,4023,4024],{"class":82},"ip",[65,4026,1286],{"class":86},[65,4028,101],{"class":86},[65,4030,4031,4033,4036,4038,4040,4042,4044,4046,4048,4050,4053,4055],{"class":67,"line":239},[65,4032,1046],{"class":78},[65,4034,4035],{"class":82}," attempts",[65,4037,1052],{"class":86},[65,4039,91],{"class":90},[65,4041,1259],{"class":86},[65,4043,1262],{"class":82},[65,4045,110],{"class":86},[65,4047,1508],{"class":94},[65,4049,116],{"class":349},[65,4051,4052],{"class":82},"key",[65,4054,140],{"class":349},[65,4056,101],{"class":86},[65,4058,4059],{"class":67,"line":417},[65,4060,1120],{"class":349},[65,4062,4063,4065,4067,4070,4072],{"class":67,"line":429},[65,4064,1530],{"class":90},[65,4066,1533],{"class":349},[65,4068,4069],{"class":82},"attempts",[65,4071,1539],{"class":349},[65,4073,1542],{"class":86},[65,4075,4076,4078,4081,4083,4086,4088,4090,4092],{"class":67,"line":441},[65,4077,2495],{"class":78},[65,4079,4080],{"class":82}," count",[65,4082,1052],{"class":86},[65,4084,4085],{"class":94}," parseInt",[65,4087,116],{"class":349},[65,4089,4069],{"class":82},[65,4091,140],{"class":349},[65,4093,101],{"class":86},[65,4095,4096,4098,4100,4103,4106,4109,4111],{"class":67,"line":447},[65,4097,3115],{"class":90},[65,4099,1533],{"class":349},[65,4101,4102],{"class":82},"count",[65,4104,4105],{"class":86}," >=",[65,4107,4108],{"class":1092}," 5",[65,4110,1539],{"class":349},[65,4112,1542],{"class":86},[65,4114,4115],{"class":67,"line":453},[65,4116,4117],{"class":71},"        \u002F\u002F Brute force detectie\n",[65,4119,4120,4123,4125,4128,4130,4132,4134,4136,4138],{"class":67,"line":458},[65,4121,4122],{"class":90},"        await",[65,4124,1259],{"class":86},[65,4126,4127],{"class":94},"handleBruteForce",[65,4129,116],{"class":349},[65,4131,569],{"class":82},[65,4133,192],{"class":86},[65,4135,3979],{"class":82},[65,4137,140],{"class":349},[65,4139,101],{"class":86},[65,4141,4142],{"class":67,"line":478},[65,4143,1237],{"class":86},[65,4145,4146,4148,4150],{"class":67,"line":484},[65,4147,3231],{"class":86},[65,4149,3234],{"class":90},[65,4151,344],{"class":86},[65,4153,4154,4156,4158,4160,4162,4164,4166,4168,4170,4172,4174,4176,4179,4181,4183,4185],{"class":67,"line":503},[65,4155,2532],{"class":90},[65,4157,1259],{"class":86},[65,4159,1262],{"class":82},[65,4161,110],{"class":86},[65,4163,1267],{"class":94},[65,4165,116],{"class":349},[65,4167,4052],{"class":82},[65,4169,192],{"class":86},[65,4171,3209],{"class":1092},[65,4173,192],{"class":86},[65,4175,492],{"class":86},[65,4177,4178],{"class":122},"1",[65,4180,184],{"class":86},[65,4182,140],{"class":349},[65,4184,143],{"class":86},[65,4186,4187],{"class":71}," \u002F\u002F 5 minuten TTL\n",[65,4189,4190],{"class":67,"line":526},[65,4191,651],{"class":86},[65,4193,4194],{"class":67,"line":547},[65,4195,153],{"emptyLinePlaceholder":152},[65,4197,4198],{"class":67,"line":588},[65,4199,4200],{"class":71},"    \u002F\u002F Log login attempt\n",[65,4202,4203,4205,4207,4209,4211,4213],{"class":67,"line":598},[65,4204,1256],{"class":90},[65,4206,1259],{"class":86},[65,4208,1351],{"class":82},[65,4210,110],{"class":86},[65,4212,179],{"class":94},[65,4214,1270],{"class":349},[65,4216,4217,4219,4222,4224],{"class":67,"line":615},[65,4218,1363],{"class":86},[65,4220,4221],{"class":122},"INSERT INTO login_attempts (email, ip, success, timestamp) VALUES (?, ?, ?, ?)",[65,4223,184],{"class":86},[65,4225,500],{"class":86},[65,4227,4228,4230,4232,4234,4236,4238,4240,4242,4244,4246],{"class":67,"line":632},[65,4229,1376],{"class":349},[65,4231,569],{"class":82},[65,4233,192],{"class":86},[65,4235,3979],{"class":82},[65,4237,192],{"class":86},[65,4239,3988],{"class":82},[65,4241,192],{"class":86},[65,4243,1071],{"class":86},[65,4245,920],{"class":94},[65,4247,4248],{"class":349},"()]\n",[65,4250,4251,4253],{"class":67,"line":648},[65,4252,1329],{"class":349},[65,4254,101],{"class":86},[65,4256,4257],{"class":67,"line":654},[65,4258,819],{"class":86},[65,4260,4261],{"class":67,"line":660},[65,4262,153],{"emptyLinePlaceholder":152},[65,4264,4265,4267,4270,4272,4274,4276,4278,4280,4282,4284,4286,4288,4290,4292,4294,4296],{"class":67,"line":665},[65,4266,1001],{"class":78},[65,4268,4269],{"class":349}," handleBruteForce",[65,4271,116],{"class":86},[65,4273,569],{"class":1009},[65,4275,353],{"class":86},[65,4277,356],{"class":340},[65,4279,192],{"class":86},[65,4281,3979],{"class":1009},[65,4283,353],{"class":86},[65,4285,356],{"class":340},[65,4287,1027],{"class":86},[65,4289,1030],{"class":340},[65,4291,1033],{"class":86},[65,4293,4001],{"class":340},[65,4295,1039],{"class":86},[65,4297,344],{"class":86},[65,4299,4300],{"class":67,"line":681},[65,4301,4302],{"class":71},"    \u002F\u002F Blokkeer IP tijdelijk\n",[65,4304,4305,4307,4309,4311,4313,4315,4317,4319,4322,4324,4326,4328,4330,4333,4335,4337,4339,4341,4343,4345],{"class":67,"line":701},[65,4306,1256],{"class":90},[65,4308,1259],{"class":86},[65,4310,1262],{"class":82},[65,4312,110],{"class":86},[65,4314,1267],{"class":94},[65,4316,116],{"class":349},[65,4318,119],{"class":86},[65,4320,4321],{"class":122},"blocked_ip:",[65,4323,126],{"class":86},[65,4325,4024],{"class":82},[65,4327,1286],{"class":86},[65,4329,192],{"class":86},[65,4331,4332],{"class":1092}," 3600",[65,4334,192],{"class":86},[65,4336,492],{"class":86},[65,4338,4178],{"class":122},[65,4340,184],{"class":86},[65,4342,140],{"class":349},[65,4344,143],{"class":86},[65,4346,4347],{"class":71}," \u002F\u002F 1 uur blokkering\n",[65,4349,4350],{"class":67,"line":721},[65,4351,1120],{"class":349},[65,4353,4354],{"class":67,"line":756},[65,4355,4356],{"class":71},"    \u002F\u002F Notificeer beheerder\n",[65,4358,4359,4361,4363,4366,4368],{"class":67,"line":765},[65,4360,1256],{"class":90},[65,4362,1259],{"class":86},[65,4364,4365],{"class":94},"notifyAdmin",[65,4367,116],{"class":349},[65,4369,1542],{"class":86},[65,4371,4372,4375,4377,4379,4381,4383],{"class":67,"line":781},[65,4373,4374],{"class":349},"      type",[65,4376,353],{"class":86},[65,4378,492],{"class":86},[65,4380,3835],{"class":122},[65,4382,184],{"class":86},[65,4384,500],{"class":86},[65,4386,4387,4390],{"class":67,"line":797},[65,4388,4389],{"class":82},"      email",[65,4391,500],{"class":86},[65,4393,4394,4397],{"class":67,"line":811},[65,4395,4396],{"class":82},"      ip",[65,4398,500],{"class":86},[65,4400,4401,4404,4406,4408,4410],{"class":67,"line":816},[65,4402,4403],{"class":349},"      timestamp",[65,4405,353],{"class":86},[65,4407,1071],{"class":86},[65,4409,920],{"class":94},[65,4411,1232],{"class":349},[65,4413,4414,4416,4418],{"class":67,"line":822},[65,4415,3231],{"class":86},[65,4417,140],{"class":349},[65,4419,101],{"class":86},[65,4421,4422],{"class":67,"line":1338},[65,4423,819],{"class":86},[65,4425,4426],{"class":67,"line":1344},[65,4427,153],{"emptyLinePlaceholder":152},[65,4429,4430,4432,4435,4437,4439,4441,4443,4445,4448,4450,4452,4454,4456,4458,4460,4462],{"class":67,"line":1360},[65,4431,1001],{"class":78},[65,4433,4434],{"class":349}," detectSuspiciousActivity",[65,4436,116],{"class":86},[65,4438,1989],{"class":1009},[65,4440,353],{"class":86},[65,4442,356],{"class":340},[65,4444,192],{"class":86},[65,4446,4447],{"class":1009}," activity",[65,4449,353],{"class":86},[65,4451,3899],{"class":340},[65,4453,1027],{"class":86},[65,4455,1030],{"class":340},[65,4457,1033],{"class":86},[65,4459,4001],{"class":340},[65,4461,1039],{"class":86},[65,4463,344],{"class":86},[65,4465,4466],{"class":67,"line":1373},[65,4467,4468],{"class":71},"    \u002F\u002F Detecteer verdachte activiteit\n",[65,4470,4471,4473,4476,4478,4480,4482,4484,4486,4488],{"class":67,"line":1418},[65,4472,1046],{"class":78},[65,4474,4475],{"class":82}," recentLogins",[65,4477,1052],{"class":86},[65,4479,91],{"class":90},[65,4481,1259],{"class":86},[65,4483,1351],{"class":82},[65,4485,110],{"class":86},[65,4487,179],{"class":94},[65,4489,1270],{"class":349},[65,4491,4492,4494,4497,4499],{"class":67,"line":1425},[65,4493,1363],{"class":86},[65,4495,4496],{"class":122},"SELECT * FROM login_attempts WHERE user_id = ? AND timestamp > ?",[65,4498,184],{"class":86},[65,4500,500],{"class":86},[65,4502,4503,4505,4507,4509,4511,4513,4515,4517,4519,4521,4523,4526,4528,4530,4532,4534,4536,4538,4540],{"class":67,"line":1430},[65,4504,1376],{"class":349},[65,4506,1989],{"class":82},[65,4508,192],{"class":86},[65,4510,1071],{"class":86},[65,4512,920],{"class":94},[65,4514,116],{"class":349},[65,4516,1078],{"class":82},[65,4518,110],{"class":86},[65,4520,1083],{"class":94},[65,4522,1086],{"class":349},[65,4524,4525],{"class":86},"-",[65,4527,1093],{"class":1092},[65,4529,1096],{"class":86},[65,4531,1099],{"class":1092},[65,4533,1096],{"class":86},[65,4535,1099],{"class":1092},[65,4537,1096],{"class":86},[65,4539,1108],{"class":1092},[65,4541,1415],{"class":349},[65,4543,4544,4546],{"class":67,"line":1440},[65,4545,1329],{"class":349},[65,4547,101],{"class":86},[65,4549,4550],{"class":67,"line":1445},[65,4551,153],{"emptyLinePlaceholder":152},[65,4553,4554,4556,4558,4561,4563,4565,4568,4571,4573],{"class":67,"line":1450},[65,4555,1530],{"class":90},[65,4557,1533],{"class":349},[65,4559,4560],{"class":82},"recentLogins",[65,4562,110],{"class":86},[65,4564,1650],{"class":82},[65,4566,4567],{"class":86}," >",[65,4569,4570],{"class":1092}," 10",[65,4572,1539],{"class":349},[65,4574,1542],{"class":86},[65,4576,4577],{"class":67,"line":1484},[65,4578,4579],{"class":71},"      \u002F\u002F Verdachte activiteit gedetecteerd\n",[65,4581,4582,4584,4586,4588,4590],{"class":67,"line":1490},[65,4583,2532],{"class":90},[65,4585,1259],{"class":86},[65,4587,4365],{"class":94},[65,4589,116],{"class":349},[65,4591,1542],{"class":86},[65,4593,4594,4597,4599,4601,4604,4606],{"class":67,"line":1527},[65,4595,4596],{"class":349},"        type",[65,4598,353],{"class":86},[65,4600,492],{"class":86},[65,4602,4603],{"class":122},"suspicious_activity",[65,4605,184],{"class":86},[65,4607,500],{"class":86},[65,4609,4610,4612],{"class":67,"line":1545},[65,4611,3388],{"class":82},[65,4613,500],{"class":86},[65,4615,4616,4619],{"class":67,"line":1566},[65,4617,4618],{"class":82},"        activity",[65,4620,500],{"class":86},[65,4622,4623,4626,4628,4630,4632],{"class":67,"line":1571},[65,4624,4625],{"class":349},"        timestamp",[65,4627,353],{"class":86},[65,4629,1071],{"class":86},[65,4631,920],{"class":94},[65,4633,1232],{"class":349},[65,4635,4636,4639,4641],{"class":67,"line":1576},[65,4637,4638],{"class":86},"      }",[65,4640,140],{"class":349},[65,4642,101],{"class":86},[65,4644,4645],{"class":67,"line":1582},[65,4646,651],{"class":86},[65,4648,4649],{"class":67,"line":1604},[65,4650,819],{"class":86},[65,4652,4653],{"class":67,"line":1616},[65,4654,450],{"class":86},[24,4656,4657],{},[30,4658,831],{},[34,4660,4661,4664,4667,4670],{},[37,4662,4663],{},"Detecteert brute force aanvallen",[37,4665,4666],{},"Monitort verdachte activiteit",[37,4668,4669],{},"Automatische IP blokkering",[37,4671,4672],{},"Beheerder notificaties",[24,4674,4675,4677],{},[30,4676,1824],{}," Security verbeterde met 90% door proactieve monitoring",[19,4679,4681],{"id":4680},"performance-resultaten-samenvatting","Performance Resultaten Samenvatting",[4683,4684,4685,4701],"table",{},[4686,4687,4688],"thead",{},[4689,4690,4691,4695,4698],"tr",{},[4692,4693,4694],"th",{},"Optimalisatie Stap",[4692,4696,4697],{},"Performance Verbetering",[4692,4699,4700],{},"Security Verbetering",[4702,4703,4704,4718,4731,4744,4757],"tbody",{},[4689,4705,4706,4712,4715],{},[4707,4708,4709],"td",{},[30,4710,4711],{},"OAuth2 Multi-Provider",[4707,4713,4714],{},"2x snellere login",[4707,4716,4717],{},"Verminderde wachtwoord problemen",[4689,4719,4720,4725,4728],{},[4707,4721,4722],{},[30,4723,4724],{},"Session Management",[4707,4726,4727],{},"60x snellere validatie",[4707,4729,4730],{},"Betere session security",[4689,4732,4733,4738,4741],{},[4707,4734,4735],{},[30,4736,4737],{},"Two-Factor Authentication",[4707,4739,4740],{},"Geen performance impact",[4707,4742,4743],{},"2FA security",[4689,4745,4746,4751,4754],{},[4707,4747,4748],{},[30,4749,4750],{},"Performance Optimalisatie",[4707,4752,4753],{},"15x snellere authenticatie",[4707,4755,4756],{},"JWT security",[4689,4758,4759,4764,4766],{},[4707,4760,4761],{},[30,4762,4763],{},"Security Monitoring",[4707,4765,4740],{},[4707,4767,4768],{},[30,4769,4770],{},"90% betere security",[19,4772,4774],{"id":4773},"belangrijkste-lessen-geleerd","Belangrijkste Lessen Geleerd",[316,4776,4778],{"id":4777},"_1-authenticatie-moet-veilig-en-snel-zijn","1. Authenticatie Moet Veilig EN Snel Zijn",[34,4780,4781,4784,4787],{},[37,4782,4783],{},"Performance en veiligheid kunnen gebalanceerd worden",[37,4785,4786],{},"Caching verbetert performance zonder security impact",[37,4788,4789],{},"JWT tokens bieden stateless authenticatie",[316,4791,4793],{"id":4792},"_2-multi-provider-support-verbetert-ux","2. Multi-Provider Support Verbetert UX",[34,4795,4796,4799,4801],{},[37,4797,4798],{},"OAuth2 providers verminderen wachtwoord problemen",[37,4800,842],{},[37,4802,4803],{},"Unified interface vereenvoudigt implementatie",[316,4805,4807],{"id":4806},"_3-session-management-is-kritiek","3. Session Management Is Kritiek",[34,4809,4810,4813,4816],{},[37,4811,4812],{},"Redis caching verbetert performance dramatisch",[37,4814,4815],{},"Database backup zorgt voor betrouwbaarheid",[37,4817,4818],{},"Automatische TTL voorkomt session leaks",[316,4820,4822],{"id":4821},"_4-two-factor-authentication-is-essentieel","4. Two-Factor Authentication Is Essentieel",[34,4824,4825,4827,4829],{},[37,4826,2628],{},[37,4828,2631],{},[37,4830,2634],{},[316,4832,4834],{"id":4833},"_5-security-monitoring-voorkomt-threats","5. Security Monitoring Voorkomt Threats",[34,4836,4837,4840,4843],{},[37,4838,4839],{},"Proactieve monitoring detecteert aanvallen",[37,4841,4842],{},"Automatische blokkering voorkomt brute force",[37,4844,4845],{},"Beheerder notificaties voor security events",[19,4847,4849],{"id":4848},"implementatie-checklist","Implementatie Checklist",[24,4851,4852],{},"Als je authenticatie wilt optimaliseren:",[34,4854,4857,4870,4879,4888,4897,4906,4915,4924],{"className":4855},[4856],"contains-task-list",[37,4858,4861,4865,4866,4869],{"className":4859},[4860],"task-list-item",[4862,4863],"input",{"disabled":152,"type":4864},"checkbox"," ",[30,4867,4868],{},"Implementeer OAuth2 providers",": Google, Microsoft, GitHub",[37,4871,4873,4865,4875,4878],{"className":4872},[4860],[4862,4874],{"disabled":152,"type":4864},[30,4876,4877],{},"Optimaliseer session management",": Redis caching, database backup",[37,4880,4882,4865,4884,4887],{"className":4881},[4860],[4862,4883],{"disabled":152,"type":4864},[30,4885,4886],{},"Voeg Two-Factor Authentication toe",": TOTP, SMS, email",[37,4889,4891,4865,4893,4896],{"className":4890},[4860],[4862,4892],{"disabled":152,"type":4864},[30,4894,4895],{},"Implementeer JWT tokens",": Stateless authenticatie",[37,4898,4900,4865,4902,4905],{"className":4899},[4860],[4862,4901],{"disabled":152,"type":4864},[30,4903,4904],{},"Voeg security monitoring toe",": Brute force detectie",[37,4907,4909,4865,4911,4914],{"className":4908},[4860],[4862,4910],{"disabled":152,"type":4864},[30,4912,4913],{},"Optimaliseer database queries",": JOINs, caching",[37,4916,4918,4865,4920,4923],{"className":4917},[4860],[4862,4919],{"disabled":152,"type":4864},[30,4921,4922],{},"Implementeer refresh tokens",": Lange sessies",[37,4925,4927,4865,4929,4932],{"className":4926},[4860],[4862,4928],{"disabled":152,"type":4864},[30,4930,4931],{},"Test onder belasting",": Zorg dat performance behouden blijft",[19,4934,4936],{"id":4935},"samenvatting","Samenvatting",[24,4938,4939],{},"Het optimaliseren van authenticatie vereist een uitgebreide aanpak. Door OAuth2 multi-provider support, geoptimaliseerde session management, Two-Factor Authentication, performance optimalisatie en security monitoring te combineren, bereikten we veilige, snelle authenticatie voor al onze applicaties.",[24,4941,4942],{},"De sleutel was begrijpen dat authenticatie niet alleen gaat over veiligheid—het gaat over het creëren van een complete authenticatie strategie die veiligheid waarborgt terwijl optimale performance en gebruikerservaring behouden blijft.",[24,4944,4945],{},"Als dit artikel je hielp authenticatie strategieën te begrijpen, kunnen we je helpen deze technieken te implementeren in je eigen applicaties. Bij Ludulicious specialiseren we ons in:",[34,4947,4948,4954,4959],{},[37,4949,4950,4953],{},[30,4951,4952],{},"Authenticatie Strategieën",": Veilige, snelle gebruikersbeheer",[37,4955,4956,4958],{},[30,4957,4763],{},": Proactieve threat detectie en preventie",[37,4960,4961,4964],{},[30,4962,4963],{},"Custom Development",": Op maat gemaakte authenticatie oplossingen",[24,4966,4967],{},[30,4968,4969],{},"Klaar om je authenticatie te optimaliseren?",[24,4971,4972,4977],{},[4973,4974,4976],"a",{"href":4975},"\u002Fcontact","Neem contact op"," voor een gratis consultatie, of bekijk onze andere security gidsen:",[34,4979,4980,4986,4992,4998,5004],{},[37,4981,4982],{},[4973,4983,4985],{"href":4984},"\u002Fblog\u002Fdomain-structure-challenges","Domain Structuur Uitdagingen: Wanneer Klanten Niet Weten Wat Ze Willen",[37,4987,4988],{},[4973,4989,4991],{"href":4990},"\u002Fblog\u002Fclient-communication-strategies","Client Communicatie Strategieën: Vertrouwen Bouwen Door Transparantie",[37,4993,4994],{},[4973,4995,4997],{"href":4996},"\u002Fblog\u002Fproject-estimation-challenges","Project Estimation Uitdagingen: Onzekerheid Beheren in Softwareontwikkeling",[37,4999,5000],{},[4973,5001,5003],{"href":5002},"\u002Fblog\u002Ftechnical-debt-management","Technical Debt Management: Snelheid en Kwaliteit Balanceren",[37,5005,5006],{},[4973,5007,5009],{"href":5008},"\u002Fblog\u002Fteam-collaboration-tools","Team Collaboration Tools: Effectieve Remote Development",[5011,5012],"hr",{},[24,5014,5015],{},[5016,5017,5018],"em",{},"Deze optimalisatie case study is gebaseerd op echte productie ervaring met authenticatie systemen. Alle performance cijfers zijn van echte productie systemen.",[5020,5021,5022],"style",{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":60,"searchDepth":75,"depth":75,"links":5024},[5025,5026,5027,5032,5036,5040,5041,5048,5049],{"id":21,"depth":75,"text":22},{"id":287,"depth":75,"text":288},{"id":313,"depth":75,"text":314,"children":5028},[5029,5030,5031],{"id":318,"depth":104,"text":319},{"id":854,"depth":104,"text":855},{"id":1828,"depth":104,"text":1829},{"id":2645,"depth":75,"text":2646,"children":5033},[5034,5035],{"id":2649,"depth":104,"text":2650},{"id":2860,"depth":104,"text":2861},{"id":3796,"depth":75,"text":3797,"children":5037},[5038,5039],{"id":3800,"depth":104,"text":3801},{"id":3908,"depth":104,"text":3909},{"id":4680,"depth":75,"text":4681},{"id":4773,"depth":75,"text":4774,"children":5042},[5043,5044,5045,5046,5047],{"id":4777,"depth":104,"text":4778},{"id":4792,"depth":104,"text":4793},{"id":4806,"depth":104,"text":4807},{"id":4821,"depth":104,"text":4822},{"id":4833,"depth":104,"text":4834},{"id":4848,"depth":75,"text":4849},{"id":4935,"depth":75,"text":4936},[14,5051],"Authenticatie","2025-01-17","Leer moderne authenticatie strategieën voor webapplicaties, van OAuth2 flows tot session management. Echte wereld implementatie patronen die veiligheid waarborgen terwijl optimale performance en gebruikerservaring behouden blijft.","md",{"src":5056},"https:\u002F\u002Fpicsum.photos\u002Fid\u002F16\u002F640\u002F360",{},"\u002Fblog\u002Fauthentication-strategies",{"title":5,"description":5053},"blog\u002F12.authentication-strategies",[5051,14,5062,4724,5063,5064,5065],"OAuth2","Gebruikersbeheer","JWT","Performance","9lZ9RWgwVdCa5F3hLVqeFFC9uUnB9s5tQvzc7wjy4Ok",[5068,5071],{"title":4985,"path":4984,"stem":5069,"description":5070,"children":-1},"blog\u002F11.domain-structure-challenges","Leer hoe je domain structuur uitdagingen kunt navigeren wanneer klanten onzeker zijn over hun vereisten. Echte wereld strategieën voor het verzamelen van vereisten, het beheren van scope creep, en het leveren van succesvolle projecten ondanks onduidelijke initiële specificaties.",{"title":5072,"path":5073,"stem":5074,"description":5075,"children":-1},"SaaS Architectuur Patronen: Schaalbare Applicaties Bouwen","\u002Fblog\u002Fsaas-architecture-patterns","blog\u002F13.saas-architecture-patterns","Leer bewezen SaaS architectuur patronen voor het bouwen van schaalbare, multi-tenant applicaties. Echte wereld strategieën voor database design, API architectuur en deployment die groei van startup tot enterprise schaal aankunnen.",[]]