As I understand it, the following chain of events occurs in OAuth 2 in order for Site-A
to access User's information from Site-B
.
Site-A registers on Site-B, and obtains a Secret and an ID. When User tells Site-A to access Site-B, User is sent to Site-B where they tell Site-B that they would indeed like to give Site-A permissions to specific information. Site-B redirects User back to Site-A, along with an Authorization Code. Site-A then passes that Authorization Code along with its Secret back to Site-B in return for a Security Token. Site-A then makes requests to Site-B on behalf of User by bundling the Security Token along with requests.
How does all of this work in terms of security and encryption, on a high level? How does OAuth 2 protect against things like replay attacks using the Security Token?
code
) but there are other grant types defined in OAuth 2.0 that are relevant for different use cases (e.g. non-user related ones).
How OAuth 2.0 works in real life:
I was driving by Olaf's bakery on my way to work when I saw the most delicious donut in the window -- I mean, the thing was dripping chocolatey goodness. So I went inside and demanded "I must have that donut!". He said "sure that will be $30."
Yeah I know, $30 for one donut! It must be delicious! I reached for my wallet when suddenly I heard the chef yell "NO! No donut for you". I asked: why? He said he only accepts bank transfers.
Seriously? Yep, he was serious. I almost walked away right there, but then the donut called out to me: "Eat me, I'm delicious...". Who am I to disobey orders from a donut? I said ok.
He handed me a note with his name on it (the chef, not the donut): "Tell them Olaf sent you". His name was already on the note, so I don't know what the point of saying that was, but ok.
I drove an hour and a half to my bank. I handed the note to the teller; I told her Olaf sent me. She gave me one of those looks, the kind that says, "I can read".
She took my note, asked for my id, asked me how much money was ok to give him. I told her $30 dollars. She did some scribbling and handed me another note. This one had a bunch of numbers on it, I guessed that's how they keep track of the notes.
At that point I'm starving. I rushed out of there, an hour and a half later I was back, standing in front of Olaf with my note extended. He took it, looked it over and said, "I'll be back".
I thought he was getting my donut, but after 30 minutes I started to get suspicious. So I asked the guy behind the counter "Where's Olaf?". He said "He went to get money". "What do you mean?". "He take note to bank".
Huh... so Olaf took the note that the bank gave me and went back to the bank to get money out of my account. Since he had the note the bank gave me, the bank knew he was the guy I was talking about, and because I spoke with the bank they knew to only give him $30.
It must have taken me a long time to figure that out because by the time I looked up, Olaf was standing in front of me finally handing me my donut. Before I left I had to ask, "Olaf, did you always sell donuts this way?". "No, I used to do it different."
Huh. As I was walking back to my car my phone rang. I didn't bother answering, it was probably my job calling to fire me, my boss is such a ***. Besides, I was caught up thinking about the process I just went through.
I mean think about it: I was able to let Olaf take $30 out of my bank account without having to give him my account information. And I didn't have to worry that he would take out too much money because I already told the bank he was only allowed to take $30. And the bank knew he was the right guy because he had the note they gave me to give to Olaf.
Ok, sure I would rather hand him $30 from my pocket. But now that he had that note I could just tell the bank to let him take $30 every week, then I could just show up at the bakery and I didn't have to go to the bank anymore. I could even order the donut by phone if I wanted to.
Of course I'd never do that -- that donut was disgusting.
I wonder if this approach has broader applications. He mentioned this was his second approach, I could call it Olaf 2.0. Anyway I better get home, I gotta start looking for a new job. But not before I get one of those strawberry shakes from that new place across town, I need something to wash away the taste of that donut.
Based on what I've read, this is how it all works:
The general flow outlined in the question is correct. In step 2, User X is authenticated, and is also authorizing Site A's access to User X's information on Site B. In step 4, the site passes its Secret back to Site B, authenticating itself, as well as the Authorization Code, indicating what it's asking for (User X's access token).
Overall, OAuth 2 actually is a very simple security model, and encryption never comes directly into play. Instead, both the Secret and the Security Token are essentially passwords, and the whole thing is secured only by the security of the https connection.
OAuth 2 has no protection against replay attacks of the Security Token or the Secret. Instead, it relies entirely on Site B being responsible with these items and not letting them get out, and on them being sent over https while in transit (https will protect URL parameters).
The purpose of the Authorization Code step is simply convenience, and the Authorization Code is not especially sensitive on its own. It provides a common identifier for User X's access token for Site A when asking Site B for User X's access token. Just User X's user id on Site B would not have worked, because there could be many outstanding access tokens waiting to be handed out to different sites at the same time.
OAuth is a protocol with which a 3-party app can access your data stored in another website without your account and password. For a more official definition, refer to the Wiki or specification.
Here is a use case demo:
I login to LinkedIn and want to connect some friends who are in my Gmail contacts. LinkedIn supports this. It will request a secure resource (my gmail contact list) from gmail. So I click this button: A web page pops up, and it shows the Gmail login page, when I enter my account and password: Gmail then shows a consent page where I click "Accept": Now LinkedIn can access my contacts in Gmail:
Below is a flowchart of the example above:
https://i.stack.imgur.com/bt7k0.png
Step 1: LinkedIn requests a token from Gmail's Authorization Server.
Step 2: The Gmail authorization server authenticates the resource owner and shows the user the consent page. (the user needs to login to Gmail if they are not already logged-in)
Step 3: User grants the request for LinkedIn to access the Gmail data.
Step 4: the Gmail authorization server responds back with an access token.
Step 5: LinkedIn calls the Gmail API with this access token.
Step 6: The Gmail resource server returns your contacts if the access token is valid. (The token will be verified by the Gmail resource server)
You can get more from details about OAuth here.
Figure 1, lifted from RFC6750:
+--------+ +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+
This is how Oauth 2.0 works, well explained in this article
https://i.stack.imgur.com/Mo2wi.jpg
This is a gem:
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
Very brief summary:
OAuth defines four roles:
Resource Owner Client Resource Server Authorization Server
You (Resource Owner) have a mobile phone. You have several different email accounts, but you want all your email accounts in one app, so you don't need to keep switching. So your GMail (Client) asks for access (via Yahoo's Authorization Server) to your Yahoo emails (Resource Server) so you can read both emails on your GMail application.
The reason OAuth exists is because it is unsecure for GMail to store your Yahoo username and password.
https://i.stack.imgur.com/6CMie.png
The other answer is very detailed and addresses the bulk of the questions raised by the OP.
To elaborate, and specifically to address the OP's question of "How does OAuth 2 protect against things like replay attacks using the Security Token?", there are two additional protections in the official recommendations for implementing OAuth 2:
Tokens will usually have a short expiration period (https://www.rfc-editor.org/rfc/rfc6819#section-5.1.5.3):
A short expiration time for tokens is a means of protection against the following threats: replay...
When the token is used by Site A, the recommendation is that it will be presented not as URL parameters but in the Authorization request header field (https://www.rfc-editor.org/rfc/rfc6750):
Clients SHOULD make authenticated requests with a bearer token using the "Authorization" request header field with the "Bearer" HTTP authorization scheme. ... The "application/x-www-form-urlencoded" method SHOULD NOT be used except in application contexts where participating browsers do not have access to the "Authorization" request header field. ... URI Query Parameter... is included to document current use; its use is not recommended, due to its security deficiencies
Here is perhaps the simplest explanation of how OAuth2 works for all 4 grant types, i.e., 4 different flows where the app can acquire the access token.
Similarity
All grant type flows have 2 parts:
Get access token
Use access token
The 2nd part 'use access token' is the same for all flows
Difference
The 1st part of the flow 'get access token' for each grant type varies.
However, in general the 'get access token' part can be summarized as consisting 5 steps:
Pre-register your app (client) with OAuth provider, e.g., Twitter, etc. to get client id/secret Create a social login button with client id & required scopes/permissions on your page so when clicked user gets redirected to OAuth provider to be authenticated OAuth provider request user to grant permission to your app (client) OAuth provider issues code App (client) acquires access token
Here is a side-by-side diagram comparing how each grant type flow is different based on the 5 steps.
This diagram is from https://blog.oauth.io/introduction-oauth2-flow-diagrams/
https://i.stack.imgur.com/kC8bX.png
Each have different levels of implementation difficulty, security, and uses cases. Depending on your needs and situation, you will have to use one of them. Which to use?
Client Credential: If your app is only serving a single user
Resource Owner Password Crendential: This should be used only as last resort as the user has to hand over his credentials to the app, which means the app can do everything the user can
Authorization Code: The best way to get user authorization
Implicit: If you app is mobile or single-page app
There is more explanation of the choice here: https://blog.oauth.io/choose-oauth2-flow-grant-types-for-app/
To be honest, I did not find among the answers one that answers the question "How does OAuth 2 protect against things like replay attacks using the Security Token?", which is the main one.
First, the access scheme described by OP only applies to one of the flows provided by OAuth 2.0 - Authorization Code Grant. There are other flows. One of the common features of all flows is that as a result of successful authentication, the client receives an access token.
How can you protect yourself from replay attacks? This is possible (with some reservations), but you need to understand that, firstly, this requires a set of measures (described below), and secondly, you can’t just protect yourself 100% from this type of attack, sometimes you can stop unauthorized access attempts right away , sometimes you can only shorten the duration of such an attack if it occurs.
So what do you need for this:
Use signed JWT as your tokens. Use a very short expiration time for access tokens, 10 minutes is enough in my opinion. Your authorization server must issue refresh tokens, which is generally optional according to the standard. The expiration time of refresh tokens should not be too long, for each situation it should be solved differently, for example, for a website, I would set it a little longer than a normal user session. You can also implement session expiration when the user is idle, but this applies to the application logic and is not provided for by the standard (this is a fairly simple mechanism, but it's out of the scope of the question). You must store issued refresh tokens in the authorization server database. However, you don't have to store access token data to take advantage of self-contained JWTs. It is advisable to store data about refresh tokens during the lifetime of the session, that is, until the time when the refresh token expires (in fact, it will not be one token, but a family - more on that below). Take general measures to protect against token/session theft, they are probably well-known, among them are the following: use only a secure connection; if you store tokens on the end user side using cookies, set cookie flags to protect them, more details here; implement protection against cross-site request forgery (CSRF), more details here. (Now the most interesting part begins) Implement refresh token rotation. This means that every time a client uses a refresh token to get a new access token (because the access token has expired), a new refresh token must be issued along with the new access token, and the old refresh token must be invalidated. It could just be a flag in the database indicating that the refresh token is invalid. Each time the authorization server issues a refresh token, it must add to it (among other required/recommended) the following claims: jti with a unique token id and a private claim with any unassigned public name, e.g. fid with unique token family id (within one session). For example, refresh token 1 had jti 3c30a712-247b-4091-b692-8c3e92b83bb2, fid 4eb44450-84e9-4fbc-830e-33935e20f7e6, after issuing refresh token 2 instead of refresh token 1, it might have a new jti f467cf40-8cd7-485e-8711-b5c657832fc6 but will have the same fid 4eb44450-84e9-4fbc-830e-33935e20f7e6. You keep holding the entire refresh token family in the database until the last one, the one that is still valid, becomes invalid, for example, until it expires. *You can do without the fid claim, then you will have to link the entire chain / family of refresh tokens issued within the same session using relational database mechanisms. Implement an absolute expiration time for refresh tokens. Each time, when the authorization server within the same session issues a new refresh token instead of the previous refresh token, the value of its exp claim should not exceed the expiration time of the very first refresh token. For example, if refresh token 1 had a value of 1643384057 for exp claim, then each subsequent refresh token, for example refresh token 5, should also contain the same value 1643384057 in the exp claim. Implement refresh token replay (reuse) detection. Perhaps you have already guessed what to do next. Each time the authorization server receives a request to issue an access token, the authorization server, among other things, must check whether the presented refresh token is one from an existing chain / family and is not marked invalid. If an authorization server receives an invalidated refresh token that is in a family that has a valid (latest) refresh token, it MUST invalidate the most recent refresh token (no valid tokens left) and MUST refuse to issue an access token.
What happens when an attacker steals a token/session and tries to reuse it. There are several scenarios:
The token/session was used by the attacker before, at the request of a legitimate user, the client requested the issuance of new access and refresh tokens. That is, the attacker managed to do it first. Then, at the next request of a legitimate user, the client will send an invalid refresh token to the authorization server (because the attacker made the request earlier and the legitimate user's refresh token was invalidated). The session will be invalidated. The token/session was used by a legitimate user, and the stolen token/session was later used by an attacker. In this case, the same thing will happen - the session will be invalidated, I think this is understandable. It is possible that after the token/session was stolen, the legitimate user did not send any more requests, then the attacker will have access until the absolute expiration of the refresh token (see point 9).
The authorization server cannot know who is a legitimate user and who is an attacker, so in such a situation the last (valid) refresh token is always invalidated, making the session expired / invalid. After that, a legitimate user can verify his identity by entering a password, and an attacker cannot.
Understanding how this works, you should choose values related to token expiration that are relevant to your project.
I recommend that you take a deeper look at the related standards, as well as the OAuth 2.0 Security Best Current Practice. There you will also find the Token Replay Prevention section.
OAuth2, by itself, doesn't protect you against replay attacks. However, there are "extensions" like MTLS or DPoP that can be used. You can find out more at https://marcinjahn.com/technologies/security/oauth2/sender-constraint.html
Success story sharing