 Authentication done right. So we're gonna talk about my journey of creating a federated login system or like you can call it single sign-on server in Node.js. I have a disclaimer in the beginning. I am like, don't consider me a expert in Node.js or cybersecurity, should do your due diligence when you're creating authentication system, figure out things on your own, definitely. And this is like, I don't want it to appear like a best practices talk. I would like presented more like the things that we did, things, some of them that went wrong, what we did to fix that. Maybe when you're making a similar system, some of these things might be helpful for you. So to start with, what did we build? Like, I mean, what kind of a system do you call SSO, whether it's a federated identity management system or LDAP? So here's what we needed actually. Something very simple. We wanted a single system in which users can log in using external service providers. If they want to, like they can use a Twitter login or Facebook login or something like that. And we have like a lot of different client apps. So we have one e-learning app, we can watch videos. We have an app where people can participate in a lot of contests. So like a microservice kind of architecture. So there are a lot of different apps and people should be able to like log in with a single identity. So there are two parts to it. One part is an OAuth client, which helps us get people logged in to our system for using some other third-party server. So like the upper part of the system. So they can log in using some other systems. And of course, we do have support for local logins. That is keeping an account with a username and password on the system, not use a third-party login if they want to. So things that we're using to build it. So we're using PostgreSQL as a database be equipped for saving the passwords. And one of the most beautiful things that we're using, so the last talk you heard was also from OAuth0. And they have a beautiful service which allows you to create like a completely outsourced identity management system. What I really like is that everything that they have used to build their own system, a lot of those tools are open source. So you can literally create a copy of OAuth0 on your own, which like our system is much like that, using their own tools. So passport, common library for authentication using Node.js, it's made by the people who have built OAuth0. Then there's the second part to the system which is the OAuth server, which is a system which allows all of our client apps to be able to use a single login system. Basically the lower half of this. So there might be some systems that use authentication plus they also use user roles for doing some ACL. There is, we have an app which basically needs the GitHub data of the user to give some scores and all. Then there could be some apps which do some two way data updates also. Like users information can be changed from the client app on the SSO server, other way around as well. And to do this, we are using a Node.js library called OAuth2 ORIZE. The first version was called OAuth ORIZE and they just added two in the middle to call it OAuth2 ORIZE. It is a very simple way to create a OAuth 2.0 server. You don't need to implement a lot of things by hand. And we're using stuff for sending emails for verification and stuff. And we have SpeakEasy, it's a library made by a lot of Googlers which helps you use Google Authenticator or any time-based OTP methods. So when you went out building it, a few of the things that we had in mind right from the beginning, like basic tenets that will definitely follow these things is these. First, Node JavaScript. So speaking at a JavaScript conference, Node JavaScript, I mean Node JavaScript on the front end. So our system does not rely the login server only. I'm not talking about the client apps. They are all, some of them are Ember apps, some of them are Vue.js apps. I'm talking about the authentication system itself, does not rely on any front-end JavaScript. So we just completely eliminate the case of XSS. No cross-site scripting to be handled at all. I mean, and also our cookies are then HTTP-only cookies. And I mean, for perspective, there is, if you try out, you disable JavaScript in your browser, try out most of the Google services, try out Gmail, try out Google search, they work perfectly. So you can build pretty complex stuff without using JavaScript on the front end. And that's the way the web was built at one point of time in the past. So, and it helps in security. For saving the passwords, you're using Bcrypt. And I think this is something I have seen a lot of people and even we ourselves, we experimented with a few things here and there. And it really boils down to, you like, just keep it simple, Pbkdf or Bcrypt, these two are some of the best methods. We are using sorts, but we are not using Pepper. I think for the kind of scale that we operate on, the kind of attacks that we can possibly face, I don't think Peppers are not needed. I think it would be an overkill to do that. Then, so if you're creating an authentication system and you want like, a lot of your products are using the same authentication system, and in today's day and age, I think one thing you definitely should have is allow users to opt into 2FA. Unless you're a bank or something like that, you might want to enforce 2FA, but otherwise, even if you're making a simple product, you should at least let people opt into 2FA. You can maybe use some OTP generation methods via SMS and email or something like that, but, or you can use OTHI or Google Authenticator, so use a TOTP solution for that. Okay, so pretty contrasting after the last talk, but we use JWTs a lot. We use JWTs a lot across our client apps. So when like, say for example, we have a video player, the video gets signed by a JWT. We use that JWT to download the chunks of that video. So we're doing that in a lot of our application servers. The authentication server does not use JWT because of two reasons. One of them, I told already, we are not using JavaScript on the front end. So I think one of the good ways of using JWTs, keeping it in the RAM, not in the storage. So that won't be possible if we don't use JavaScript on the front end. Two, we want server-side logouts for the central authentication system. You want that. If you don't use, if you use JWTs, you end up turning them stateful. You keep a blacklist or you keep a whitelist. And if you end up with a blacklist or a whitelist, then you are at the end of the day storing in the database, so it's better just fall back to tokens itself. Okay, that's the reason. Not using JWTs. Also, the entire knowledge that download happened here last half an hour, the developers don't need to understand that to implement the system. Because yes, JWTs is easy to implement, but to correctly implement, you have to keep in mind a lot of those things. This, I think if you're creating a single-sign-on system, this is something that we follow is that we have some mobile apps also. And in mobile apps, when we log in, the username password entering happens through a web view. We don't get the username and password on the client and then pass it over the API. We don't do that. So that's like, I think I prefer doing it this way because when you're doing it via a web view, the users can see that you are, so phishing gets prevented, man-in-the-middle attacks get prevented. The users can see if it is over HTTPS or not, which on an app, it's hard to see. It's easy for somebody to maybe decompile your app, modify it, and then fish some password or something out of it. And unless you are like somebody like Facebook or Google where people have a lot of trust on that app and they know for sure that they're using the correct app for something else, I prefer to just use a single UI for taking the password. There should be not two, three different places where the user is submitting his trust. So a few things. I think building a security system, let's decide what we cannot protect. This is very important because they are attack vectors everywhere. And if you try to protect all of them, you're gonna end up with a mess. This is one of my favorite XKCD comics that all kinds of security measures one side and you can just beat a person and get his password. Okay, so that's the case we are not covering. So very simple. If somebody shares this password, tells his password to somebody else or somebody looks at somebody typing the password, we can't protect that. And basically we're gonna protect our system. We're gonna protect till the extent of our SSL certificate. If there is any client side proxies or anything, we don't want to cover that case. It just complicates the thinking process. Like then you start thinking, okay, I'll protect against this, I'll protect against that. No point doing that. Just do the ones that are possible. Okay, this is very important. So how many of you here have used an Adharka to enter an airport? So were you identified or authenticated? So identification is just, you tell your name is something that's identification. Getting this difference clear is very important when you're creating an authorization system. Authentication, now that's when you actually verify whether the identity that has been provided is correct or not. And this authentication can happen in two ways. One is using implied trust. So if you say, for example, show your passport to somebody, and somebody sees the passport and sees that it looks authentic as in the paper and the quality of it that looks authentic. So they trust the government of India and they think that you are authentic because the passport does not look like it has been forged. The other way of authentication is what it's called tofu. Trust on first use, that is you first time meet a person, you tell that there's a secret word that we share with each other. In future, whenever I share this secret word, you know that it's me. That's the password way of doing authentication. But either you need to trust a third party to identify the person or you need to trust that person first time by default and then next, from next time, use the first trust factor, okay? So, but it is more than just identification. And then this authorization, so you have access to something, allow somebody else to use it as simple as that. That's authorization. Here, there's a question here. What's the official name of the HTTP error code 401? Unauthorized or what? Authorized? 403? For a bit, okay. Somebody who is logged in can they get a 401 error? And somebody who is logged out can they get a 403 error? Okay, can the same route generate a 401 and a 403 in different use cases? Okay, so I think, Mushad answers correct? 401, the name is unauthorized, but it actually means unauthenticated. With a HTTP, as per the HTTP spec, the name is unauthorized, but it does not mean unauthorized. It means unauthorized. And forbidden is what actually means unauthorized. So, only when you're not logged in, you can get unauthorized. When you're logged in, but you don't have access to that particular route, you get a forbidden, okay? This brings us to authentication via authorization. So, quick example, you want to prove that you own a house, you can show the sale deed or property certificate or something like that. The other way to prove it, you invite somebody home. They assume it's your house. Okay, so that's authentication or authorization. You authorize somebody to use your house. It's implied that you own that house. Okay, so when we're doing OAuth, we're doing something very similar to this. Let's just take a look. The steps go like this. You go to a browser. Browser sends a request to server. It gives you a login page. You got a login page. Click login with GitHub, okay? Browser sends a request to GitHub now and it adds some client ID redirect to your eyes so that GitHub knows which app is trying to log in. Okay, GitHub sends me back the GitHub login page. GitHub login page, I add my username and password. Now, this is going to post request to GitHub. The challenge will get verified, username and password are correct or not. I'm not sharing my username or password with the coding blocks app. Sharing only with GitHub, okay? And now there are two ways forward, okay? Red Pill Blue Pill. We've got implicit way and explicit way of authenticating from here forward. So let's look at what implicit way means. So GitHub redirects me back to my website and the URL contains the OAuth token. Okay, so at this point, I'm already trusting that my browser has opened my website correctly. It's implied trust there. And now if I want to get my profile details, my profile page can simply make our Ajax request to say api.github.com slash profile pass this header OAuth token equal to something. I will get name, email, username. And see this is where authentication of authorization is happening. I get the name, email and username from GitHub. So I authorized this app to get my profile information and the app takes this profile information and it just trust that this name and this email is correct. So I think this Blue Pill, this is Red Pill, explicit author case, GitHub takes me back to my website but this time it gives a grant code instead of a OAuth token. Now for this to work, obviously you need your backend server. This cannot work on only front end base systems. You have to pass the grant code, you get OAuth token, pass the OAuth token, get your profile data, then you show your profile page. So this is the kind of system we are using. This need not have front end JavaScript to work. You can do the actual transfer in the backend. If you laid out all the steps together, this is what the implicit steps look like. This is what the explicit steps look like. So when you do a fetch client page, then that information is actually exchanged. Okay, so while you're building this, things that we learned, sometimes we burned our fingers on certain things. I think the first thing, and you have had two security talks and lot of the things might have been like captain obvious and here is one of the captain obvious slides, but this is important. We ran the system for, I think more than one year, had about 10,000 users till that point. We did not have CSRF protection. We did not have a content security policy and that's like the story of a lot of startups. Just start building things. Prototype, prototype becomes production. You don't know when it becomes production. Okay, users start pouring in. Your friends and family are using tomorrow, like people are using, but I mean, as much as possible, not do this. I mean, first time you do this, maybe second time you make an app, don't do this because one major problem we had is you were actually saving the sessions in memory. We had to, when we had to scale up, we created cluster mode. I mean, it did not even hit me first. Some guy says, I'm trying to log into your website. I logged in, but when I refresh the page, sometimes the page opens, sometimes it says I'm logged out. I'm like, sometimes, what do you mean by sometimes? Okay, and so what happened was that, depending on the kind of name resolving strategy you're using in NGINX, my requests were all being served by one of the clusters, not by the second one. Somebody else was using, their IP was rotating and sometimes they're using node one, sometimes node two, and their token is in the memory of node one, not in node two, okay? You can't scale if you save stuff in memory, of course. It took us three, four days to figure out, okay, that's the problem here. So, here's like, after doing this, I think with the transport layer stuff, I think we figured out basic security versus overkill kind of checklist. Using X frame options, probably using deny so that people cannot put your website inside an iFrame. That's a good option to do. Content security policy, keeping one, definitely very useful. I can recommend looking up GitHub's engineering blog. They have a very nice article on how to do content security policy, okay? Should ideally have a specific CDN which sends your images, styles, and fonts, and you whitelist that in your content security policy because XSS via images are seeing one of the easiest way people do. Don't do that, keep a whitelist for that. And, this is the place where you can actually, with a hard switch, you can disable JavaScript on the front end. You can use script SRC and pass an empty area to script SRC. In that case, no JavaScript will get executed on your site at all, okay? Some websites and production level, like Facebook, GitHub, what they do is, they have a separate CDN from where they send their JavaScript files, okay? And the script SRC does not contain self, which means any lines of code part of the HTML does not get executed. Only the JavaScript that comes from the CDN gets executed. Okay, so like if there are some Chrome extensions or somebody man-in-the-middle injecting JavaScript into your page, that does not work out, okay? CSR protection, very easy to do these days in Node.js, you see surf, replay the token. This is something, basic hygiene should be done, of course. Okay, this is very important. I know a lot of people who think this way that if you're using a very popular SQL library, you're using an ORM, statements are always prepared, so you don't need to worry about SQL injection. It's a problem solved in the bygone era, but it's not, so like just last year in SQLize, the most popular ORM in Node.js, two vulnerabilities on SQL injection was found out. It was patched, current version does not have any, but you never know when a new feature that started an SQL injection might get added to it. Okay, so for this, I think you can read up a nice article by Snick, SNYK, it's also a good tool to check out whether your code has vulnerabilities and all. So I mean, this is a strategy security experts say, defense in depth, validate your variables at every layer, validate on the client, if you have client JavaScript, if not, then M layer, V layer, C layer, every layer, validate the input, okay? Don't just think that in one layer, you're validated next layer, it will come out to be validated automatically, okay? And rock varies and all, if you are doing that, of course, manually escape stuff. This thing also we learned is that we download a RFC paper and we see, okay, the spec is fine. You start implementing one thing, two things. You find one thing, okay, refreshed tokens, okay? There are, you have to make a post call, then a get call and all of that. Okay, I will just make a separate endpoint which will refresh my tokens, okay? So just maintaining everything, 90% of the spec you're following, you take one little shortcut, it bites you in the back later on. And we have now figured this out, we never sidestep the specs ever doing things like this. So the refreshed token thing was something that we implemented our own way of doing refreshed token server to server refreshed token calls without using the user scope. And that obviously first of all created a vulnerability. Second, the thing is in security, I think once insecure, if you are having a mobile app or a PW or something like that, where you cannot control the rate at which people are updating their clients, then once it is insecure, it's going to remain insecure for a long time. Because if you have an API which is insecure, now you update to a secure API, the clients stop working. You don't know, business guys won't allow that to happen. They will say, okay, keep the old API open for two months, wait for the people to update. Till then, you know there is a vulnerability and you're living with that vulnerability. You can't get out of that. Either you delete like 10,000 users who are using that every day, they stop using it, something like that will happen. Okay, so turning things insecure and then turning it back to secure very hard. You go out of the spec, you sometimes risk certain things like that happening. Another one incident is we initially thought that, people will always log in using a user scope. But then some client might want to edit data, not using a user scope, like as a client itself. The OAuth spec supports this. We thought such a case will never happen. We had to rewrite a lot of our project to support such things. For OAuth, I think some of the things that you can defer, not ignore, is say refresh tokens. You can make that people will just log in once again if their tokens have expired. But don't implement a different way to refresh token. Either don't implement it at all. That's fine. Similarly, scopes and all for clients, you can use a star scope for everything. And later on, you can add scopes if you want to. Okay. And one thing I know what is something called a password grant type, like I said with the single UI model. Don't support a scheme where the username and password can be sent over a post request and you can give a grant type. That exists so that OAuth 2 is compliant with OAuth 1. It's a backwards compatibility thing, but it makes OAuth insecure. It's better not to implement that. This, now coming more towards the business side aspects of creating a system like this and whether things that not work out well and we had to. So state management is a very important part of UX and I'd like to show you a couple of things. So here is a zero login system. So what does zero login mean? So I'm, this is one of our client apps and I'm logged into that right now. If I go to another of my client apps, so I'm logged in. Okay. So, I mean basically when I went to the online.coding.com, this site I did not have to log in again. Other ways, if I am on one of the apps and in any other tab I have logged in, I can click on login and I get logged in automatically. So, I mean saying say one click login and two click login path, which is like if I click on login and I'm not logged in right now, then I can either put my challenge or I can use one of the social providers and if I'm logged into the social provider, then two clicks takes me to log in. Finally, if I'm not logged in anywhere. Okay. So in that case, I have of course it'll be a three click model but then I have to log into Facebook also. Okay. Then there's another case which I call as the broken flow model. Somebody comes to our website and they don't have account with our website now and they click on login, takes me to the single sign on server. There they sign up with their account. Okay. They sign up but some of our products, they need a verified email ID to use it. Okay. They don't work only with a simple sign up. You have to verify your email ID also for to be able to use it. Okay. But at this point, their flow breaks because they now have to open their inbox, check the verify link, open that very filing. Okay. So this is the place where a lot of systems I've used even popular ones like Kora and all I've seen. This is where flow breaks from a lot of times you click on the verify link. You don't end up at the exact page where you started your entire cycle from. Okay. So you should ideally like make a redirect where I part of the verify link itself or I think that's not an information you'd probably want to share over emails. That's fine. You attach the redirect part in database to your verify email link so that if somebody like signs up and then they have to check their inbox. So at that point, a lot of drop happens. Sometimes people just leave using that and maybe next day they come and click on the verify email link. Okay. So when the next they click on the verify email link, okay. Capture the user back at the same point in your product where he left. So he was probably added something in his cart. We'll go and buy it. Okay. If he ends up at my profile page, you will not provide it. Okay. This is very important in the broken flow model also. You should end up at the same place where he started from. And now about the part where when we have a SSO server and a lot of client apps. So we need to separate our concerns also. We need to make sure that first thing there's the data API. So the client apps use the user API to get the details of the user. So whenever data fetching is happening, that should always happen over the version API. So that if you change the API of the SSO, you don't need to rewrite the code in all your client apps. Okay. If like different apps need different sets of data, you can create scopes for them. The authentication flow, like how we are logging in via Facebook or how we are logging in by Twitter or how we are giving our challenge. That part of the flow is not related to the client apps. That is purely in the SSO level. So that part, if we change, we don't need to version that. That part we can change on our own, that's fine. But whenever the client apps are accessing data from the SSO app, make it version. This, I think we have done a lot of to and fro on this and we have ended up with a thumb rule on what kind of data should we save on the SSO server, what kind of data we should not save. Is if some data needs to be there on at least more than two of our client apps, then only we think of centralizing it. And keep in mind that if it is not related to user data, and this is like a lazy developer thing, you think that some information, like information of all, like the demographics, like country, state information, et cetera, we need it in a lot of apps. Okay, let's just put it in the SSO server because everybody is using SSO server. It's just going to slow down your SSO server needlessly. Okay, if you need like global information across to 10 of your clients, just create a separate microservice of that. Don't dump things into the SSO server just because it's globally used everywhere, only as long as it pertains to the user data. If it is about the user data, then. And this you should always maintain this thing is that if we need in one of our client apps, we need information about the GitHub user profile or like Facebook user profile we need. Those queries should happen via the SSO server so that your trust chain always remains on the SSO side. Okay, like that way it can happen is like we can get a Facebook authentication token, pass it on to a client app, but then in the client app, you will have to implement the Facebook refresh token mechanism also. You just end up rewriting that all the time. So if the user has done a third party authentication in the SSO server, accessing data office third party authentication should have happened through the same flow itself. Then this is challenging keeping data in sync across these things. Some of the data will obviously become redundant. Maybe name of the user profile photo. You might keep a copy in the client apps also in the SSO app. So when it is really important to keep the data in sync, then every authentication just refresh the data from the SSO server. Otherwise, like if it's not all that critical then you can maybe run some crons, et cetera for updating that data. And if you have like data updates on the SSO server, then do not like create any generic like special APIs. Just do it using the proper STPI using the user's auth token scope. So every client app should be treated equally. Nobody should have like a special hook to like change an entire table on the database. That's where security flaws start happening. We've also found out that whenever you want to implement things, if you just take a little bit of time out to find out if some specifications exist for that, some standards exist that has had better results. One example specifically was all countries, states, cities in the world, they have ISO 3611 code which uniquely identifies every like region. If you use that, you can use that as primary keys because the ISO standard ensures that it is unique. We have migrated that a lot of times finally and ended up using the spec. Okay, so this analytics and monitoring, I'll show you something. Anybody remembers getting emails from Twitter or GitHub? How your passwords are probably logged? I think a lot of people got these, okay? And it was widely speculated, though none of them actually verified. They both use a similar logging, Ruby-based logging framework and it was speculated that they were actually using a log all framework which was logging the entire request bodies and that's why your passwords were getting logged. So whenever you're using log all kind of frameworks, make sure you're sanitizing the log values. Lot of libraries, they remove specific keys like if you have a key name, password, they will probably delete that but still you should manually do that. In addition to that, if you have compliance and legal issues, keep in mind that when you're using third party monitoring services, then the user's data does not stay with you, it goes to somebody else. You need to maybe talk with your lawyer if you're a big company. We don't have a lawyer, we are a tiny company. Okay, use like standard HTTP error codes also. They like your analytics monitoring software, they have some default behavior if you're using proper error codes. This famous Akanun article about this or if you put your username and password on Stripe or GitHub, they say that username or password is incorrect. They don't tell which one is incorrect but then you can go to the sign up form and check if the username is correct or not. Okay, so not telling whether the username is correct or not can have a benefit only if there is no easy way to find out if the username is correct or not. Okay, most of the web-based applications you try to sign up, people can get to know if the username was correct or not. Okay, so you're not reducing the attack vector just by not telling the user whether the username was correct or not. Rather if you exactly tell if the username or the password was not correct, the user will rectify only that part. Okay, so you're just confusing the user. I mean, we did this, we ended up with the situation. People are not able to log in, just why can't you log in? We call up the user, I can log in. I just can't, he can't describe anything beyond that. Okay, so now we make it a point that, I mean, as long as the user, the error can make sense to a layman, we pass that error on, like the message is more specific. You don't like the server failed or something like that, not that kind of errors, more specific. So it helps us debug production errors better. This thing, when we are doing a third party authentication with services like Google, Facebook and all, after Cambridge Analytica, they have been cleaning house a lot. A lot of times this happens, an example from discuss, like this is current example. If you try to log in with Google and discuss, it will not work because Google Plus, they have disabled certain profiles, go up on that. So if you just want to do login, for that part, don't take an extra scope, other than just the profile scope. When you need extra information, do a loop back across that provider once again. That the user sign up cycle does not break. A lot of times say, if you want to do Google sign in with Google, it is very seamless, but if you ask extra permissions, then you get a page like this. Okay, and this page out of our data, I mean we have like 20, 30,000 users, don't have a lot of data, but we have seen a lot of dropout from this place. Like if you ask for extra profile scopes, people don't give these permissions. It's very common. So if you just need to log in, just log in and most of these service providers, they don't ask anything extra during the login part. Later on, if you need other things, do it later. I mean, common stuff, try to stay generic. So don't try to create like specific use cases kind of things. Then, I mean, this is one thing we have been trying to figure in a lot of ways, how to handle the duplication part, deduplication. I think you need to segregate between two things in mind is, somebody deliberately creating a new email account and trying to log in is different from somebody mistakenly having created two accounts, one with the Facebook login, one with Twitter login. So when sometimes you need to allow people to merge their accounts and if you think that your business case depends on identifying a user so that he cannot use two accounts to use some coupons or some benefits, it's India, forget that, okay? That's not going to work out. People are going to create multiple accounts and they're going to use that. So if your business model depends on that, I don't think that's going to work out. And finally, secure even from yourself. This is very, very, very important is that when you're like having slowly your development team will grow. Start with one person, there's a founder, there's a CTO, then the team grows, there's 10 people, 20 people. Right from day one, make sure that you keep a copy of your database run a cron job that anonymizes all the data and then you check across the anonymized database. It's a good practice to have from day one. Later on, it will be hard to implement, okay? Second point, I mean, I don't know how many people would agree, but our system is completely open source and that has helped made it secure a lot because every time we make a git commit and push, we know that the world is going to see this code. So we just make sure that, you know, there is no security flaw in that code. It's like two times we're thinking about that. All of our products which are closed source, there are only two, three of them. They are much more insecure than the open source one. That I can say for sure, okay? So to summarize, security is pretty simple. I think these two things are things you can keep in mind. A lot of people say that making things secure reduces the experience. I think it does not reduce the experience of the user, but it definitely does reduce the experience of the developer, okay? You are going to create a lot of barriers for yourself when you make your system secure, but that's a cost on you, not the cost on your users. You can keep things with very nice UX plus security. That's easy to do. And yeah, just follow the security tips that you have known from the beginning. And I will just end my presentation with a nice joke here. I don't know how many of you might have seen this in Twitter. This is one guy who complained to T-Mobile Austria that the call center person was verifying their password over call. So he said that means the call center person has access to my password, which means that it is probably saved in plain text, okay? Also not case sensitive. Wait, it's not end here. T-Mobile says the customer service doesn't see the first four characters only, not the other ones, okay? So we store the whole password because we needed to log in? Of course. So they go on saying that you have so many passwords for every app, for every email account, so on we secure all data very carefully, so there is nothing to fear, okay? And then somebody comes up and says, what if your infrastructure gets breached and everyone's password is published to plain text to the whole wide world? What if this does not happen because our security is amazingly good, okay? It does not end here. The guy says he has to come back. This is that nobody's security is that good, not even yours. T-Mobile Austria has to always come back to that. You're saying that do you have any idea of how telecommunication companies work? Do you know anything about our systems? Apparently that guy has to work at Dodge Telecom. So that guy has experience working with telecommunication systems. So don't act like T-Mobile Austria. Think security is something we should always just keep learning and advice wherever it comes from. Hear it, research on your own. I don't think anybody knows everything about security. We are all learning every day. So building the system, my inspirations were Stack Exchange Network. It has a very nice dual layer SSO system log in with a lot of things into Stack Exchange. They have a lot of sites and has Geek's own last user system. So that's something I looked upon a lot but I'm not so comfortable with Python. Otherwise I would have used that. I wrote my own one. And two people I would like to thank, Jared Hansen, our chief architect at Auth0. He, without his libraries making a lot of these things would not have been possible. Aaron Hammer, author of Oath 1.0 and he has written a very big blog article criticizing Oath 2.0. I read that. I figured out which parts of Oath 2.0 are useful and which parts are not. So thank you. If you want to see the source code of this system when I'm describing, it's at github.com slash coding block slash one Oath. If you want to see it in action, it's account.codingblows.com. You want to follow me on Twitter.