I've seen a number of articles posted here recently that just give terrible advice when it comes to OAuth2, so I figured I'd make this so people would dick themselves over.
The reason people do this, is because they are just writing filler nonsense content in the hopes you'll click on the website. They don't care if the content is solid because they just want you to see the ads.
As for my credentials, I work for a major fintech company with part of my duties being to help developers get set up with OAuth2 in their applications.
If you aren't a lazy fuck, just read this, and the next section on decoupling. Otherwise I've summarised the important bits later on.
Note: If your shit is on-prem only and protected by a firewall, none of this matters if you trust your employees. I'm assuming your stuff is external facing to the public.
Never, under any circumstances, should you validate any tokens in your application. You will do one of two things.
- Fuck it up
- Not update when you need to
There will be times when you are unable to update the SDKs that run your app (think about when microsoft got rid of crystal reports from visual studio). You can put yourself in a situation where there is a known security flaw and you are unable to patch it. Don't do this.
Decoupling your token validation from your app is a simple prospect. You need one of two things.
- A proxy: In the case you have a server side rendered application and you use cookies to auth with. You want a proxy with openid connect support.
- A gateway that can validate bearer tokens with a JWKS URI. Use this in front of your API when using a SPA, or machine to machine auth.
The AWS way of doing this would be to use ALB with openid connect or to use an HTTP API with a JWT authorizer.
If you are fully on-prem, look for open source projects with these capabilities. Also make sure you have scheduled maintenance where you can update these pieces. Since they are separate from your application, it should be simple.
At this point if you've read the IETF document you can leave, but since you haven't, read on.
There is only one correct method. Use asymmetric keys with JWKS (JSON Web Key Set). This will allow you to regularly rotate the keys with zero downtime. It will also set you up to be fully compatible with pretty much anything that needs to validate a token (HTTP APIs in AWS for example only support this method).
Asymetric keys also mean that if a server gets owned, you don't need to worry about hackers making tokens with valid signatures. This is because they will only have the public side of the key, not the private one needed for generating valid tokens.
There are only two grant types you should care about. client_credentials
, which is what you use for machines to talk to one another and and authorization_code
which you use when you need to authenticate a user. client_credentials
is stupid easy, just make sure you don't commit the client_secret
to code and you're gucci.
authorization_code
is a lot more complicated, and it's the part you are most likely to fuck up, so please use a well tested library. If you can, also use PKCE on top. This will make it more secure, at the cost of more steps for you to dick up the process.
The basic flow of auth code (without PKCE) is this.
- You generate a nonce (random string).
- You direct the user to the auth provider, passing the nonce with them.
- They log in
- They get redirected back to you with a code (not an access token), and the nonce, which you validate.
- You then make a request to the auth provider with the code, and get the real access token (plus maybe a refresh token).
The nonce is to stop CSRF attacks, and the flow itself is to stop the access token from existing in the browser's history.
You have the option to use refresh tokens with authorization_code
. These are more long lasting tokens that aren't used for access, but allow the user to request a new set of access/refresh tokens. Refresh tokens generally have a long life, and they are stored in the database of the auth provider due to this.
Make absolutely sure that the refresh tokens you are using are single use and are deleted right after usage (before the tokens are returned to the user). Also it wouldn't be a bad idea to build in a method to delete all refresh tokens after a password change.
Please don't fuck up auth. Also take the time to read the IETF documents for OAuth2. It'll be boring as fuck, but you'll be way more prepared. Also if you notice, there's an expiration date to the document of October 2020 (the current version was released in April 2020 for reference). It's a very living document because we learn new things all the time.