0

As I understand it, OAuth is the natural evolution of authentication protocols

I understand in a general way that evolution is as follows:

  1. basic authentication
  2. cookies
  3. tokens, at this point you want to separate the front from the back.
  4. OAuth, OpenID connect ... a centralized way of handling authentication and having authorization and authentication servers.

Cookies are a way of not sending usernames and passwords in each request. When the front is separated from the back, the front and back servers do not have a common origin, so they cannot share cookies, cookies with http-only are no longer the best option ...

And if you keep growing, with different applications, in different places that share a session and third-party authentication methods, OpenID connect I understand is the protocol.

But I have entered to inspect the requests of the sites that I use daily, such as social networks, StackOverflow, and google apps... and to my surprise, I didn't find any trace of tokens or OAuth redirects.

Why do big sites use cookies for authentication, even when they are a single page app?

Are there any security features that make cookies more secure than tokens?

Why don't I see OpenID connect redirects when entering the sites and jwt in the headers?

  • in theory jwt allows horizontal scaling
  • OpenID connect allows you to use REST APIs, separate authentication and authorization servers, delegate authentication to external sites... etc. Why do big sites only use it for login with social networks and not the rest of the protocol?

Do you know any big site that uses OAuth to maintain the session and not only for the login with social networks?

I know that I have not been strict in the use of some concepts, but I think the general idea is understood and my doubt is not to discuss whether token and cookie are different things. Most of these ideas can be read on the spring authentication guide website.

8
  • 1
    The OAuth token may be compromised the same way the password can be compromised. To be honest I see no different between them, but OAuth is definitely a PITA to use. Aug 18 at 5:22
  • 2
    @ArtemS.Tashkinov the point of OAuth is access delegation, e.g. grant a third party access to some resource without ever giving that third party secret information. You can't do that with password authentication. If you see no difference between password authentication and OAuth, I'd argue that you don't know OAuth, which isn't really about authentication, but authorization.
    – vidarlo
    Aug 18 at 7:35
  • 1
    "grant a third party access to some resource without ever giving that third party secret information" - never seen it used this way. Aug 18 at 19:30
  • i.imgur.com/MrZEBRp.png -If you press sign in with Google (or Facebook), Stack Exchange won't learn your google credentials. They'll get a confirmation from google on that you're really whom you claim to be, but no credentials. In addition I'd suggest the answer to this very question for further explanation of the authorization part.
    – vidarlo
    Aug 20 at 17:32
  • 1
    @vidarlo Taking the case of stackoverflow, it uses oauth to delegate authentication to external sites, once logged in the application uses cookies and I don't see any traces of openidconnect or tokens. Openidconnect, provides a flow to call the resource server based on jwt, once logged in
    – user60108
    Aug 21 at 21:29

1 Answer 1

8

Hmm. I think there's a lot you don't understand, here. Tons of sites do use OAuth (and often OIDC) for initial authentication, StackExchance (optionally) being one of them.

To answer the closest version of your question that makes sense:

Why don't any sites use pure OAuth without any sessions?

The simple answer is that it would be extremely slow and enormously wasteful. Imagine the performance impact of adding an extra two client-side round trips (one redirecting the client from the resource server - e.g. StackOverflow - to the Authorization server - e.g. Google - and then a second one redirecting it back) plus often a back-end round-trip (to exchange the returned OAuth authorization code for an access token) on every single authenticated request! (Remember that a single web page may have hundreds of authenticated components, such as images, posts, comments, likes/reactions, user styles, user info such as name, and more; many of these are typically sent in their own request/response pairs but are processed in parallel.) For this reason, OAuth resource servers typically use only a single OAuth redirection (at login) and then establish a local session (typically using cookies or a Bearer token) for ongoing access until the session ends.

Furthermore, in its purest form, OAuth is used to grant third parties access to secure data (without giving the third party the credentials for the secure data). That's obviously useful if you're e.g. Office 365 (a Microsoft property) and want to use data from the user's Google Calendar (since Microsoft is a third party distinct from both Google and the user). It's even more useful if the resource server is some relatively untrusted site that you absolutely don't want to give unfettered access to your Google (or Microsoft, or Facebook, or Apple, or...) account. Without OAuth or another way of delegating authorization, you'd have to give that third-party site access to your credentials

However, most websites are only accessing the user's data stored in the website's provider itself (e.g. looking at your GCal on calendar.google.com, or your post on security.stackexchange.com); there is no third party, and thus no point in using OAuth. Why would Google need to ask Google whether to allow you to access your Google calendar? Why would it need to hide your Google [Calendar] credentials from Google [login]? Now, in practice, a company may use OAuth even for first-party authentication, because it provides a convenient (in the sense of "lots of client and server libraries already exist", not in the "adds no dev effort or maintenance complexity") way to transfer authentication status across domains (consider: stackoverflow.com, superuser.com, and stackexchange.com are all owned by the same company and use the same login but can't share cookies or other secret storage easily, although all *.stackexchange.com sites can amongst themselves). But for smaller sites, or sites that really only have one web property, there's just no point.

In practice, OAuth also gets used (by itself, or in combination with other protocols such as OpenID Connect a.k.a. OIDC) for implementing single-sign-on (SSO) with third-party authentication. Every site that has a "Sign in with Google" (or with Apple, or Microsoft, or Facebook, or Github, or Twitter, or...) and isn't a Google (or Apple/Microsoft/Facebook/etc.) site, it using OAuth in this way. Sites may or may not bother with OIDC on top of OAuth when doing this; OIDC is useful if you want to have a single set of profile details shared across multiple sites (so that every site knows if you change your name or whatever) but most of the time, the site that you're using SSO for only needs one unique identifier (typically your email address) and it can get that from OAuth alone and then use that to look up your account in an internal profile database.


Let's try to unpack the rest of your confusion now.

oauth is the natural evolution of authentication protocols

No.

  1. OAuth isn't exactly an authentication protocol at all, actually. It's a method for delegating authorization.
  2. This sometimes incidentally carries authentication as well (which technically you're supposed to use OpenID / OIDC for, but in practice the model is usually authorization-based-on-identity so the most succinct way to transmit authorization is just to transmit one uniquely identifying value, and you can do that with OAuth alone). Even OIDC is still just delegating authentication to a third party.
  3. OAuth is fully dependent upon the existence of some concrete authorization or authentication; whoever you delegate authorization to needs to know whether any particular party is authorized to do something, and that usually boils down to knowing who they are (authentication). As such, OAuth doesn't replace the need for existing authentication protocols, it just moves them.

basic authentication
cookies
tokens, at this point you want to separate the front from the back.
oauth,openid connect ... centralized way of handling authentication and having authorization and authentication servers.

You're conflating at least three different (though related) kinds of thing here - secret (or credential) handling and transmission, credential format, session management, delegation - all of which are part of or related to actual authentication. There's not really a natural progression between these items, for a bunch of reasons.

  1. HTTP Basic (and Digest) Authentication is a way to send credentials in a specific format in order to authenticate (or authorize; they use the Authorization request header and the username might be blank or not identify a single user) a single request. In theory this is stateless, in keeping with the stateless nature of HTML. In practice, user agents such as browsers will only ask for the credentials once, then remember and submit them automatically on every request to create an unofficial session; getting the client to forget the credentials (end the session) actually requires non-standardized workarounds.
    • Modern replacements for HTTP Basic usually involve one or more of submitting a username and password in an HTML form, submitting an identity and then a "one-time password" (typically from an app or sent via email/SMS) also via HTML form, using WebAuthN/FIDO2, using mutual TLS (TLS with client certificates; rare on websites but common for server-to-server communication), or using an API key for the initial authentication. They then may either generate a session (see below) or not, depending on the method selected and the site/service's use case. Typically, things that require user action and/or significant server processing time, like passwords - one-time or otherwise - and WebAuthN, get a session.
  2. Cookies are a standardized means to work around the statelessness of HTTP, by requiring the client to store and transmit a server- or site-chosen string. In the general sense, they have nothing to do with authentication; all that they are for is storing state on the client in a controllable and automatically-usable way.
    • Cookies frequently store stuff that has little or nothing to do with authentication, such as a "remember my username" value, your language and theme of choice, whether you've allowed tracking cookies, and of course tracking cookies themselves for site analytics and/or advertising.
    • It is entirely possible - though unwise - to re-implement Basic or Digest auth using cookies, e.g. by having a cookie called http-authorization with a value of Basic <Base64(username|password)>. In practice, the difference between this and actual HTTP Basic auth is simply that the lifetime and scope of the credential storage can be specified in a standard manner... and that you'd need some other way (such as an HTML form) to collect the credentials in the first place and store them in the cookie and some server-side code to extract the credentials.
    • A far more sensible, and common, approach is to use cookies for sessions. The user authenticates (or otherwise demonstrates authorization) in some way, and the server generates a user-specific (and usually unique) token (a "session token") for the user-agent to store in a cookie. Subsequent requests automatically include this session token (until it expires or is deleted) and the server uses that to make authorization decisions. Session tokens can take many forms, but the two most common are opaque blobs (completely random values with no meaning, which must be stored as the key in a session-lookup table on the server) or JSON Web Tokens (JWTs, which store session or at least authorization data within themselves plus a cryptographic signature to prevent user modification or forgery, and allow servers to store less state and make fewer state-lookups but can't easily be revoked and are totally compromised if the signing key is compromised).
    • Cookies are in fact very widely used in real-world OAuth implementations. This is true both on the site that that provides the authorization / identity and the site that uses it after delegating the process (and indeed during the process itself).
    • Note that sessions don't have to use cookies! Cookies are convenient for web sites because browsers transmit them and manage lifetime automatically, but they also create vulnerabilities such as CSRF (Cross-Site Request Forgery). Storing the session token in a JS variable or other not-automatically-submitted location means the client has to do more work to submit an authenticated request (usually adding it to the HTTP Authorization header as a Bearer token, but there are other options) but offers more control and immunity to CSRF.
  3. It is not clear what you mean by "tokens" here. A token is a kind of secret that can be used for authentication (a credential), but typically one that is specific to a particular site and not user-memorized.
    • JWTs are a kind of token, but so are API keys, random opaque session tokens, refresh tokens (in form, typically identical to opaque session tokens), OAuth state values, OAuth authorization codes, OAuth access tokens (themselves typically either an opaque session token or a JWT), Bearer tokens, Kerberos tickets, anti-CSRF tokens, and many, many more (though these are most of the commonly used ones specifically as part of an authentication/authorization process over HTTP i.e. on the web).
    • "JWT", "random opaque token", and "Kerberos ticket" define the format and generation process of a token (though they aren't the only ones; e.g. not all signed tokens are JWTs and not all encrypted tokens are Kerberos tickets).
    • "API key", "session token", "refresh token", "OAuth authorization code", "OAuth state value", "access token", and "anti-CSRF token" define the purpose and use of a token.
    • "Bearer token" defines where the token is located in transmission. The logical counterpart, "cookie token", isn't a common phrase because cookies are assumed to be where most non-Bearer tokens go if used in a web context. The purpose of a bearer token is generally assumed to be authentication and its format could be random opaque, JWT, Kerberos, or something else. Tokens can also end up other places, like in custom headers, URLs (common with OAuth), message bodies, and of course parts of protocols that aren't HTTP at all.
    • Both JWTs and Kerberos tickets are designed so they can be used in situations where the token-issuing server (generally the authenticating server) and the authentication/authorization-using app (the "resource server" in OAuth-ese) are different, and might not even fully trust one another. You can do this (with sometimes-severe performance implications) with other token types though, and the main value of JWTs is in their server-side stateless nature (many JWTs are signed with an HMAC, which requires a symmetric key so the consuming server must be identical to or at least trusted by the issuing server, or else the receiving server must relay the token to the issuing server for validation which is slow).
  4. OAuth and OIDC are ways to delegate authorization and authentication to another site.
    • The other site will still need to authenticate the user, probably initially using something like username+password in an HTML form, and then creating and storing a cookie.
    • The site using OAuth will generally still want to create a local session, because OAuth is way too slow to do all the time. Even if the site is actually using the OAuth-returned access token multiple times (rather than at most once for OIDC - or just extracting the user identity from the token directly - and then forgetting about it, the way OAuth-for-SSO typically works), the OAuth-using site will want to create a session so it knows what client is associated with the returned access token (and, if relevant, refresh token).
    • The site using OAuth will typically use a cookie or similar even before authentication, to store the state parameter that is used for OAuth. This typically-random, must-be-unpredictable string is used to prevent CSRF attacks against the resource server, where an attacker could pass their own authentication server response through your browser and make the resource server think your account and the attacker's account are the same.
    • OAuth/OIDC isn't even the only protocol(s) used for delegating auth on the web, much less in general. SAML (Security Assertion Markup Language) is widely used in enterprise-scale SSO, and while Kerberos is relatively rarely used for web properties in most environments, it's very common in Windows Domain-based (and sometimes seen in other Kerberos-based) corporate networks and has built-in support in some browsers.
    • OAuth/OIDC typically only handle the initial authentication/authorization flow. One problem here is that if the user's access changes at the authentication server - e.g. they are promoted to an Administrator, or their account is locked - sites that used OAuth/OIDC won't necessarily see the change (until the next time the require the user to authenticate, typically because a session expired or was ended but sometimes for other reasons). There are other protocols that can be used to provide updated user status to third parties, though many sites that use OAuth/OIDC don't yet support them.

Why do big sites use cookies for authentication, even when they are a single page app?

Why wouldn't they? Remember, cookies aren't a method of authentication, they are a place to store a method of authentication. The stored value - the token - can be any format, from any source: locally generated random value, locally-minted JWT, remote JWT, or many other things.

In practice, nearly all sites - even SPAs, which are just a fancy way of saying "web app that breaks security scanners, can't be used without JS, and complicates bookmarking/session restore" - are loading resources primarily or exclusively from the same site (in the cookie sense, which is much broader than same origin) that the site is hosted on. For example, Gmail is a highly complex webapp, which in some cases functions as an SPA, but everything it loads is either coming from its own domain (mail.google.com, at least in the USA) or from other Google subdomains (*.google.com), all of which can share cookies just fine. Why introduce the complexity and user-experience-degradation of OAuth - which is designed for accessing third-party content - when everything is first-party?

Are there any security features that make cookies more secure than tokens?

You're still conflating cookies (a place to put things) and tokens (I assume you mean JWTs but in general, a category of thing). Many cookies on many sites use JWTs as their value! Many opaque session tokens (and other non-JWT token types) get stored in places that aren't cookies!

This question is like asking "are there any security features that make roads more secure than trucks?" The comparison doesn't make sense; these aren't the same category of object. Trucks often go on roads (and sometimes go elsewhere). Roads often contain non-truck things, which also might go elsewhere. The security features of roads (gates, barriers, patrol officers, etc.) are completely disjoint from the security features of trucks (door locks, alarms, immobilizers).

Bringing this back to web apps and authentication, the security features of cookies (Secure, HttpOnly, SameSite, Domain, etc.) are completely disjoint from the security features of tokens (bits of entropy, RNG/cipher/signing algorithms used, cryptographic key protections if relevant, scopes, resistance to timing attacks or other side channels, resistance to database compromises, etc.).

If you want to compare random opaque session tokens to JWTs, that's a meaningful comparison (note that both can go in a cookie or elsewhere):

  • Random tokens can be revoked easily, JWTs can't.
  • Forging random tokens requires write access to the DB, forging JWTs only requires learning a signing key.
  • Random tokens might be exposed in a read-only DB breach (hashing prevents this) whereas JWTs won't (though their refresh tokens - which are usually just random tokens - will if not hashed).
  • Random tokens require a lookup to verify, which can cause problems if e.g. your DB is overloaded; JWTs usually require either an HMAC (fast) or a asymmetric digital signature (slow) verification, the latter of which can be a problem if the app server is overloaded.
  • Random tokens can only be verified by their issuer; JWTs (if using asymmetric signatures) can be verified by anybody.
  • Random tokens require storing and synchronizing state, which can lead to errors due to cache coherency failures or DoS due to over-use of synchronization locks; JWTs require only synchronizing the signing/verification keys, which don't change often, and no other caching.

So, there's advantages and tradeoffs both ways. As a practical matter, JWTs are used whenever the "third parties can verify" thing is important, and opaque tokens are used in many but not all cases where it isn't. The inability to revoke JWTs means they need to have very short lifetimes for security reasons (so that if one is compromised, it becomes invalid quickly anyhow), so JWTs are typically paired with refresh tokens... which are usually random opaque tokens anyhow, so there's a sense in which JWTs get the downsides of both worlds.

Alternatively, if you want to compare cookies vs. headers (such as Authorization: Bearer) as a place to put tokens, that is also a meaningful comparison (though a very different one):

  • Cookies create CSRF risk; Bearer tokens are immune.
  • Cookies can be "HttpOnly", whereas Bearer tokens are always visible to any malicious script on your site.
  • Cookies can sometimes be planted via header injection attacks; Bearer tokens generally can't.
  • Cookies can be sent in "simple" CORS requests, whereas Bearer tokens will always require a pre-flight for cross-origin requests so it's slightly harder to mess up your CORS configuration dangerously.
  • Cookies can automatically expire after a set time; Bearer tokens have no such feature (although the token value might be self-expiring such that it becomes useless after some point).
  • Cookies can be used even with scripts severely restricted or disabled (which reduces attack surface for browsers), where as Bearer tokens require script execution on every authenticated request.
  • Cookies might accidentally be sent to placed you didn't intend (such as a subdomain owned by a third party) whereas Bearer tokens only ever go exactly where you choose to send them.

In practice, the main reason people use cookies is simply that they're convenient. Every navigation, data-retrieval, data-manipulation, and user-action request automatically includes them, so if you put your session token in one, you don't have to do anything else (except mitigate CSRF). They work basically the same way on all browsers, even really old ones that don't support things like JS local storage (less of a concern today, but it mattered for a long time) or browsers with JS outright disabled. Their security model is not good - the thing where a cookie's "site" is so much more expansive than an "origin" trips people up all the time, as do things like the distinction between "Secure" and "HttpOnly" (totally different but people are bad at remembering the distinction) - but it's generally adequate if used correctly.

Bearer tokens, by comparison, are only viable for client-script-driven apps (which, in this day of React and GraphQL and so forth, is a lot of the new apps... but there's still tons of webapps out there that do full page generation on the server in response to navigation requests and would need to be totally re-written to be client-script-driven). They do care about same-origin policy, which is good on some ways (avoids the risk of exposing a value to the wrong origin) but encouraging developers to split front-end and back-end origins is risky (if forced to configure CORS at all, people often configure it wrong, making their site much more vulnerable).

OpenID connect allows you to use REST APIs, separate authentication and authorization servers, delegate authentication to external sites... etc. Why do big sites only use it for login with social networks and not the rest of the protocol?

Why should they bother?

  • REST APIs: Don't require OAuth/OIDC, you can do it with local authentication and authorization. Also you can do it entirely on the back-end rather than having the client make the API calls, which is sometimes simpler but not quite as scalable.
  • Separate authentication and authorization [from resource] servers: you can do that without OAuth/OIDC too, so long as they're all on the same domain suffix (and they almost always are) or you're willing to relay on the back-end. Also the benefits of this aren't super clear (except specifically in SSO situations); your auth DB is usually the same as your resource DB, and is often the bottleneck, so having multiple microservices access it doesn't gain you anything.
  • Delegate authentication to external sites: This is literally the one and only thing OAuth/OIDC is for that isn't trivial on the web without it, and most sites don't want it (or at least, only want it as an option, not a mandatory behavior). For example, Facebook has their own auth system, and wants you to use it. Users also dislike it sometimes, because it's a privacy issue; if I sign into example.com with my Apple ID, now Apple knows I use example.com, and maybe I'd rather they didn't. Besides, you can do this without OAuth/OIDC; you just end up either asking the user to enter their credentials for site X into site Y (bad), mostly re-inventing OAuth (also bad; it's over-engineered for a lot of use cases but if you try to invent it from scratch you'll probably miss something important), or making the user futz with API keys (bad because any additional user-action roadblock to using your site is bad, and also even with very simple and clear instructions people will screw it up).

Wow, that turned into a long answer, but I hope it cleared some stuff up for you. Questions or comments appreciated.

5
  • I thank you very much for your extensive response, it has clarified some things for me, but perhaps my question was not the clearest. But I tried to be as brief as possible, my English is not very good. I edited the question to be more clear So according to you openidconnect is not used because it is slow because of the redirects? –
    – user60108
    Aug 18 at 15:33
  • 1
    No, OpenID Connect (OIDC) is used all over the place (although sometimes people don't bother with it and just use the OAuth access token for authentication), but it is often only used for the initial authentication to start a session. The session token might be based on the OIDC returned value or totally new to the site actually in use. Depending on the type of application and on whether or not the app is using OAuth/OIDC for anything other than SSO, there might be additional OAuth/OIDC calls over time, but most requests will simply be authenticating using the local session.
    – CBHacking
    Aug 19 at 0:11
  • 1
    There are some sites that don't bother with a local session or even a local account, and just use the returned OAuth access token (for authorization to data) and/or OIDC response (to know who the user is). Typically, this is done for third-party wrappers or plugins for a service (e.g. an "app" that extends Slack or provides a Spotify desktop widget), where the only account in question is the third-party one. Even in those cases, though, you'll only see a single redirection (at login); normal requests will either be cross-origin or will verify the JWT directly without needing to redirect.
    – CBHacking
    Aug 19 at 0:19
  • I understand that oauth is the standard for delegating authentication. But I have tried very hard and I haven't found any page that uses openidconnect or jwt for authorization.
    – user60108
    Aug 19 at 2:40
  • Taking the case of slack, it uses oauth to delegate authentication to external sites, once logged in the application uses cookies and I don't see any traces of openidconnect or jwt. If I were to follow the openidconnect standards to do a SPA, the standard says that I would have to use the AuthorizationCodeWithPKCE or ImplicitFlow flow (depending on whether the browser supports web crypto). This ends up returning a jwt that is used to call the resource server
    – user60108
    Aug 19 at 2:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.