1

I understand that oauth is an Authorization protocol, but it is possible to use it for authentication when clubbed with something like open ID Connect.

I am trying to understand why do we need an extra token in the redirect url to prove authentication. This article presents some good points about why the possession of an access token can't be treated as authentication. https://oauth.net/articles/authentication/

My question is: can't we treat the landing on redirect url as the proof of authentication instead of requiring an extra Id token as we do in open ID Connect

2 Answers 2

1

First and foremost: what flow (grant type) are you talking about? OAuth, even just OAuth 2.0, is a lot of different things. I'll mostly assume you mean authorization code / PKCE (or Implicit but please don't use Implicit) here, as those are the common flows that people get confused about. If you're using one of the flows where you (the client app) specifically pass the authentication data to the OAuth server - which is probably either the deprecated "Resource Owner Credentials" a.k.a. "password" grant or the user-agnostic, machine-to-machine "Client Credentials" grant - then that is a different story. Neither of those use a redirect URL though, so presumably you don't mean them.

Also, I'm not sure what you mean by "an extra token in the redirect url". Please skip ahead to the blockquotes two sections down if you want to address the literal form of your question.


The weird thing about this question, and about the OAuth [2.0] spec in general, is that it generally assumes people are using OAuth for something that it is not specifically intended for but which, in practice, people use it for constantly. Specifically, OAuth is NOT (by itself) intended for SSO (Single Sign On) and does NOT assume that the client application (your app) and the resource server (the intended audience of the OAuth access token) are the same (in fact, it assumes they aren't)! In other words, unless there is a third-party API that you want to access using the token you get from the OAuth server, you are not using OAuth for the thing it's intended for.

A lot of the confusion around OAuth being an authentication protocol vs. an authorization protocol goes away in the specific (very common) scenario where the client application and the resource server are the same thing or at least have the same owner and mutual trust. In other words, the scenario where you are the expected consumer of the "access token" and there is no third party, just your app and the "authorization server" that your app delegates auth (both authz and authn) to.

However, I slipped another assumption into that last sentence! It's one which the OAuth spec does NOT require and therefore generally assumes to be false: that the resource server (in this case you, who are also the owner of the client application) has chosen an OAuth server which both performs an authentication check on the user and returns a token containing a specific identity. Neither of those is required! They are typical in practice, which means people tend to treat them as "how OAuth works", but OAuth totally allows for authorization servers which merely validate that you're some authorized entity (which could be by means as simple as "you come from a trusted IP address" but is more often stuff like "somebody has, at some point in the past, authenticated from this machine but there is no promise that it's a private machine and the authentication was to authorize access for any user of the machine") and return a token saying "the bearer is authorized to access everything in scope foo" without any information about who the user is.

People tend to not consider that last paragraph, because "of course I'm not going to trust my app's authentication to a weird OAuth server that is so lax about authentication / unspecific about the user's identity!" and indeed they should not. However, it complicates attempting to understand OAuth in the context of authentication if you forget about that. OAuth allows authorization that is not authentication, and therefore if you pick an OAuth server that reliably performs authentication and returns the result of it, you are using something that is not simply OAuth, something that is more specific than OAuth and it is misleading to say "sure, you can use OAuth for authentication" because the assumptions you are making are not part of the OAuth spec.


can't we treat the landing on redirect url as the proof of authentication instead of requiring an extra Id token

By itself, absolutely not. That would be trivial to spoof; your redirection URL is not secret and there's no reliable way to restrict how / where from somebody gets there. Even if you check the Origin or Referer header (or similar) to see whether the user came from your OAuth server, that doesn't work because the user/attacker can just spoof those value using a custom request, inside or outside of the browser.

Also, this inherently fails as a method of authentication because the redirect URL doesn't inherently contain identity information. If your redirect URL is "https://gaurav5430.app.example.com/oauth/redirect", and I fire off a request to that exact URL (e.g. by clicking the link), who am I? You have no idea. Can't realistically consider my authenticated in that situation, can you?

OK fine Mr. Pedantic; obviously I meant "landing on the redirect url, and then I verified the presence and correctness of the state token or otherwise verified that this specific user had initiated this OAuth process, verified the presence of the code token and that the authorization code was issued by a trusted OAuth authorization server via successfully exchanging the authorization code for an access token, and successfully parsed the access token to ensure that it refers to a valid user which I was able to do because I'm my own resource server and therefore the intended audience of the access token". Furthermore, obviously I only trust OAuth servers that don't do the weird stuff you talk about in the paragraph above that starts "However" so I know the OAuth server authenticated the user to whatever standard I wanted and returned specific identification of that user!

Oh did you, really, all of that? Great, why didn't you say so?! I'm not a mind-reader, you see, and that's not at all "obvious"; people get this stuff wrong ALL THE TIME so I don't assume[1] it. Anyhow, yes, in that case (note that there are rather a lot of conditions on that case!), you can treat the user completing the OAuth flow (which is NOT the same as "landing on the redirect URL"!) as authenticated.

Bear in mind, though, that some of those conditions may be hard to enforce using pure OAuth.

  • For example, suppose you decide you want the user's session to end after an hour... but you allow the OAuth-based "Sign in with Microsoft", and don't bother to perform the OIDC lookup. Unless you also control the Microsoft account in question (e.g. it's a Microsoft 365 account and you control the org and enforce login and session policies), you have no way to know if the user last logged in just now during the OAuth flow, or seven years ago and has been using the same session since. In the latter case, your "session ends after an hour" control is meaningless, because an attacker can probably just refresh the app session using the long-lived Microsoft account session!
  • Alternatively, what if you're using OAuth-based "sign in with Google" and the user logs out of Google after the OAuth flow completes but while their session on your app is still valid? Maybe it's a work account and they just don't want to be distracted by work emails (or are trying to stop Google from tracking them everywhere)... or maybe they handed their device to somebody else for a while. In the latter case, you probably want to end the user's session on your app too, because the user now operating the machine is no longer the one who authenticated and the one who authenticated expressly doesn't share accounts with new person. OAuth by itself doesn't support notifying you of this! Instead, your app session will persist until the user explicitly logs out, ends the session some other way, or the session expires (assuming you have an expiry at all), and until one of those events, you won't know that the authenticated user is no longer the active user. Perhaps you're OK with this - it's valid to say "if the user wanted the other person to not have access to their account on my app, they'd have logged out of my app before handing off the device" - but maybe the user assumed that logging out of Google would log them out of everything they logged into with Google. There's a way to do that, but it requires additional work on the app developer's part, and in particular requires that the app not treat one-time OAuth flow completion as persistent authentication the way you are doing.

[1] Honestly, "assume the person designing the system is doing everything right" is literally the opposite of my job as a security engineer; a substantial part of doing this job well is to not make those assumptions and instead verify everything.

1
  • Thanks, this clarifies a lot of things. i was indeed talking about a flow where the client is the same as the resource server, and can validate the access token (and get user details from the access token)
    – gaurav5430
    Oct 5, 2022 at 20:47
1

How will you verify that the redirect response to the redirect URI was sent by the Identity Provider (IdP) and the user himself did not mock the redirect response? A proof of possession is required to verify that it was indeed sent by the IdP and that proof is signed ID Token without which a not logged in user can bypass login and use your resources indefinitely.

The OIDC flow you are questioning is used in Implicit Flow and Hybrid Flow in which the ID Token is sent with the redirect response which is the reason why these 2 flows are not better than Authorization Code Flow. Implicit being the worst among them because it also sends access token along with ID token in redirect response. Anything that is sent as url-encoded response with the redirect can be seen from browser history and can be recorded by malicious browser extensions. Authorization code flow exchanges access token and ID token via out of band channel where even the user cannot see it.

The use case of ID token extends beyond the login process. Single Sign On (SSO) web services share that ID token with each other to verify the identity of the user. That keeps the user logged in across the web domains. As ID token also expires, the user's login sessions can be centrally managed and revoked as per need.

2
  • example flow: i use Google sign in on my website, the Google oauth server returns a auth code which i can exchange for an access token. the presence of access token only can be considered as the user logged in, why does Google oauth server need to return an Id token as well ?
    – gaurav5430
    Oct 5, 2022 at 20:45
  • ID token is actually optional to request. You can choose not to request ID token after receiving the access token. But that defeats the purpose of using OIDC. If you don't want ID token that means you only care about authorization for which Oauth2 is recommended.
    – defalt
    Oct 5, 2022 at 20:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .