I just want to point out that OAuth2 by itself is NOT authentication, it's delegated authorization.
OIDC adds the openid scope and a number of other things that together turn oauth2 into delegated authentication.
OAuth2 is just a workflow. It includes authentication in its workflow to grant authorization. Stating that it’s authorization and not authentication is a bit disingenuous. You cannot really have Authorization without Authentication happening per the spec so you’re quite wrong.
OIDC is just a flavored implementation of OAuth2 workflow that calls out specific components to use. There can be other implementations of the OAuth2 workflow that are just as secure that don’t conform to OIDC.
You cannot really have Authorization without Authentication happening per the spec so you’re quite wrong.
OAuth2 has nothing to do authentication. RFC 6749 section 3.1 is quite clear on this point:
The authorization endpoint is used to interact with the resource
owner and obtain an authorization grant. The authorization server
MUST first verify the identity of the resource owner. The way in
which the authorization server authenticates the resource owner
(e.g., username and password login, session cookies) is beyond the
scope of this specification.
Saying OAuth 2 does authentication is like saying HTTP does encryption, you can bolt TLS on top, but HTTP itself is not an encryption protocol.
You’re obviously misunderstanding that the requirement “to identify the resource owner” is part of the spec. The specific manner in which that is done is left to the implementation (and thus outside the spec).
OAuth2 is just a workflow for performing authorization using an external IDP. The workflow requires an identity authentication step, hence the the presence of authentication is implicit. If your OAuth solution it does not contain the idp step - then it’s not OAuth, period. The spec does not need tell you how to perform authentication outside of how to exchange tokens via some well known endpoints. As one of the co-authors, the type of authentication performed is left undefined because it was recognized that each use case had different needs in establishing and proving identity. Hence you can have valid OAuth workflow with and without MFA, utilize Passkeys, and solutions not invented yet. My point is that Authentication is a required and implicit step in OAuth 2.0. Stating that it excludes authentication is just incorrect. OIDC is just a specific implementation of OAuth2 which provides a very specific authentication step. There can be an infinite number of OAuth2 implementations - all must have a specific authentication step otherwise they are NOT OAuth2.
I just want to point out that Linux is NOT an operating system, it's a free component of a GNU system. GNU adds the corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX.
I was pointing out that he is being needlessly pedantic by comparing his comment to the infamous Linux/GNU copypasta. Rather than pasting the entire thing here, I edited it down to match his exact phrasing, but with Linux terms instead of OAuth.
Lol! My bad! I will not hide my shame by deleting my comment. You have bested me in fair combat as the more highly skilled smart-ass, and I doff my fedora to you, good sir.
Technically, saying that many people use the GNU System isn't fully accurate. The GNU project makes the distinction of calling it the GNU/Linux system.
linux contains some proprietary portions, which while free from a monetary perspective, are at odds with the free use principles GNU has been after.
The GNU project itself has the Hurd kernel, which never really went into mainstream use, and also maintain a variety of Linux (linux-libre) that is stripped of the parts they disagree with.
Help me out here: I get an API request with a JWT, I use the JWKS to verify the JWT is from a legitimate source, I have proven you are authentically who you claim to be. I haven't verified you're authorized to use this API call though. I need to check your privileges for that, but what I do know is you did successfully complete a login because the JWT signature is an authentic one, ergo you are authentically who your JWT claims.
As I understand, you are not verifying the authentification of the user, the IdP did. Then you verify the IdP gave the user an authorization (via the token) to call your API.
Verifying the token signature is not the same as verifying the user's authN. The token only says he was authorized to make such and such requests on behalf of this user, not that the token holder is the person that was authenticated.
Verifying the user's identity requires password, 2FA and other measures to validate the correct identity. Once it's done they're issued a token saying they can interact with the app as that user.
In your example, depending on your endpoint security checks, just having a valid token is enough to authorize the request. Sometimes you need to verify the privileges (eg. admin action), sometimes you don't (edit your own profile). In both cases, you are authorizing the request based on the token. You did not verify the identity of the user (because you trust your IdP signature).
Verifying the token signature is not the same as verifying the user's authN. The token only says he was authorized to make such and such requests on behalf of this user, not that the token holder is the person that was authenticated.
I wouldn't put it that way. Even if your service is authorizing the request because of the token, that decision was not made by the token issuer - thus the issuer and the token itself are not responsible for authorization. You, as the service, made that authorization decision after verifying the user's authentic identity (though ultimately the identity itself doesn't matter to you). I think this is pedantic to the point of being reductive, same as saying, "verifying a user's password is not proof of identity, it's authorization, because it only says the person is authorized to know the user's password not that it's actually them".
I do understand what you mean by
You did not verify the identity of the user (because you trust your IdP signature).
but still, that's the point of delegating authentication to another authority - at some point you have to trust the IdP signature. And it doesn't make sense to me to say that "my service isn't involved in authenticating the user, someone else does that". The caller is passing you a token and you are resolving it to a trusted identity. That's authentication. The fact that you trusted somebody else to receive the user's password, etc. just means that you've centralized part of the authentication process, not that you skip it entirely.
Potentially, not everyone puts those claims in their JWT, so yes I agree a JWT may also declare an authentic privilege set, but generally it will definitely have an authentic identity, whether the privileges are bundled in the JWT or not
It's a token normally returned from a POST request to an Auth endpoint where the username and password are in the body of the request. The response to that request is normally something like /
{"access_token": "blahblah"}
You then use that token (which will have an expiry though it doesn't always come with a refresh token so it can be longer lived) in an API request to get data from another API endpoint.
i.e. GET /api/users/1/account-balance
Where the header contains
Authorization: Bearer blahblah
(Then it's obviously up to the backend to make sure the token is 1. Valid and 2. The requesting user is allowed to see user id 1's account balance.)
So if a token leaks, technically they aren't seeing credentials that would issue them new tokens endlessly, they'd only see a token that almost certainly has a shorter lifespan with no knowledge of how to get a new one (as the username and password aren't part of the request header).
Bearer tokens are meant for other clients, the ones that necessarily a browser.
As with everyting in this world, we had devs who had to reinvent the wheel so they came up with using Authorization header with Bearer tokens, in frontend code - for no valid reason at all - apart from, perhaps, having no clue that cookies existed.
It would be nice if curl had the ability to send cookies but alas it has been missing this very basic HTTP functionality since its first release back in 1917.
The Authorization header was created before the Cookie header. Having these headers separate allows a web server to do authentication before cookies are even handled. It also doesn't need to split the cookie to determine if authentication is happening.
I think it came from micro services. Hitting the auth service on each page request is "expensive", so the solution is to issue tokens that are valid for some period of time, to avoid network roundtrips to the auth service. I've never really seen any explanation either but that's the only one that makes sense to me.
Tokens are often short lived (e.g. a few hours) or can easily be revoked and regenerated as needed. Tokens are generated by an authorized user (e.g. the user themselves or an admin). On the authorization side, fine-grain permissions can be associated with the token to reduce what it can do so if it is compromised there's less "surface area" of attack.
Basic auth is a bigger risk as it's sending your username and password (or sometimes a user-level token). If someone were to get this, they may have a bigger attack area depending on user permissions, able to change the password, and if you reuse passwords for other accounts, those could be compromised as well.
Basic auth contains your literal credentials in plaintext format (base64, but that's just encoding). If someone intercepts that, they now have your username and password. Tokens have expiration date, so if someone intercepts your token, they can only use it for a short while.
OAuth generated tokens will (typically) have an expiration date but it's not inherent to bearer tokens. Most of the services that I interact with that use bearer tokens/api keys do not have expiration
Bearer tokens don't do anything by themselves, they're just an arbitrary string you put auth information into.
They're "more secure" than basic auth when they're used to implement a better auth scheme, like OIDC.
In one of your other comments you express skepticism about API keys, but that's because API keys are, as an auth scheme, not much better than basic auth. Their main upside is that they usually have a narrower scope. They're still long-lived creds passed as plaintext though.
In addition to what others have stated, basic auth just tells the endpoint who you are. But a bearer token while being short lived also can restrict what you are allowed to do. So user jsmith can send a bearer token that only allows certain permissions to https://somesketchyservice.com/notverytrustworthy and if the untrusted api decides to turn around and try to use your bearer token to do other things on your behalf they would likely fail because that bearer token you sent it doesn't have permission to do anything outside what it was scoped to do. If you had sent a username password then you're basically handing the keys to the castle to anyone that needs to provide services to you...
What the other guy is trying to say is that it has built-in rotation - but you can implement that in basic auth too so IMO actual advantage comes from standardization and not having to reimplement things that libraries can do for you (for both server and clients) - less room for your own mistakes. Ofc this only makes sense in the context of oauth (ie bearer being oauth and basic meaning non-oauth)- in the abstract both basic and bearer are just different notations for potentially the same thing.
Yeah, I think a lot of people conflate bearer tokens with oauth when they're not the same thing. An oauth authentication transaction can provide you with a bearer token which has a pre-defined expiration (and I completely agree is more secure) but I work with a lot of services (HubSpot, Salesforce, ServiceNow) where I'm issued a permanent bearer token as part of the user-application definition, which to me is functionally equivalent to basic authentication in that it's something that gets passed with every request and does not expire.
Oauth/OIDC isn't the only way to use bearer tokens that's better than basic auth, it's just become such a common practice that people conflate it with JWT and token-based auth in general.
Bearer tokens are short lived, doesn't have stored credentials, and extremely difficult to spoof assuming service is securely signing and verifying tokens.
Does this explain why so many websites and services do not keep you logged in if you don't access them for longer than a day or two? Perhaps because everyone uses access and refresh tokens now, and not accessing the service for a little while means your refresh token has expired?
If yes, then this is an artifact of modern authorization that drives me crazy -- it feels like I can't stay logged into anything any longer! And I'm skeptical that the security benefits of this practice outweigh the bad user experience. Why not let me stay logged in, like the websites of yesteryear? Is there really a solid security justification for it?
In all fairness, this isn't the fault of the authentication method being used. The expiration time of access and refresh tokens are determined by the team developing the software you are using. It's not an inherent limitation of access/refresh tokens. The websites you use could choose to use refresh tokens with an expiration time of months, if they wanted to.
Why not let me stay logged in, like the websites of yesteryear? Is there really a solid security justification for it?
Yes, shorter lifetimes of authentication tokens (cookies, tokens, etc.) reduce the risk of session hijacking attacks.
I honestly don't understand why session hijacking is the justification for this. Is there any way to hijack my session that doesn't involve malicious software running directly on my computer? In that case there's a lot more to be worried about, and the malicious software doesn't even need an active session to hijack an account. And if I were regularly using the account, as is generally the case with anything of great importance like, say, a Google or Amazon account, then the session hasn't expired and it could still theoretically be hijacked!
Is there any way to hijack my session that doesn't involve malicious software running directly on my computer
Certainly. For example: physical attack vectors. Your device could get lost and/or stolen, a malicious individual could access your machine while you are temporarily not present and steal your authentication state from your drive or browser. You could sell your device without ensuring that no data may be recovered from disk after a factory reset, after which someone may be able to recover this information.
Another class of attacks would be improper data storage and/or leaks on devices you have no access to. A period of improper logging configuration in one system that accidentally stores user credentials in a logging database for a period of time for instance.
In that case there's a lot more to be worried about, and the malicious software doesn't even need an active session to hijack an account
It depends. Malware that can intercept keystrokes could bypass the need to steal active session state like cookies or tokens. Though modern security guidelines encourage the use of more than one-factor in order to partially mitigate these vectors. Of note in this case is that here too the period a two factor code is valid is time limited.
And if I were regularly using the account, as is generally the case with anything of great importance like, say, a Google or Amazon account, then the session hasn't expired and it could still theoretically be hijacked!
At the risk of sounding like ChatGPT: you're right. Session lifetime management and expiration is one layer of mitgation/defense that helps mitigate certain attack vectors, but are not infallible or a silver bullet of any kind. They are one security measure of your entire defense in depth strategy.
At the risk of sounding like ChatGPT: you're right
😆
I think basically my point is that, if I had the choice to sacrifice that little bit of security, and I don't really think it's that much extra security, for the convenience and better user experience of not getting logged out, then I would do that. And I wish sites gave us that choice.
And if someone gains physical access to my device, then it's the same situation as malware: everything is compromised. It doesn't matter if there are active sessions; they have access to my email (and possibly even my phone number!) and therefore can hijack any account of mine that they want. In that situation my course is the same regardless of whether the sessions are active or not: revoke email access immediately, revoke all active sessions, change every password, pray!
Sort of. It's still possible to have a long session, but it's no longer the default, so less sites offer it. I would consider it risky if there is any payment or personal information in the profile or any messaging capabilities.
I'm skeptical that the security benefits of this practice outweigh the bad user experience.
The bad user experience could be due to the site design, or it could be from your own habits not updating over time. If you are still typing website passwords in 2025, then you need to update your habits. Logging in should be 2 extra clicks.
I'm not manually typing in passwords -- I have a password manager. But it's death by a thousand cuts. Having to log into one website is fine. Having to do it multiple times a day every day because every website behaves this way now is wearisome.
I am still fuzzy on refresh tokens. I understand on load, we can validate a token the client has in the browser. However, how do we refresh a token? Do we realize client side, and request a new token with the said refresh token? What do I do if in the middle of their session their token expires when doing a `get posts` call? How am I supposed to "update" the access token without disrupting the user?
How am I supposed to "update" the access token without disrupting the user
There's many ways. One approach would be to have some sort of background process automatically do a token refresh whenever the current token is close to expiration (e.g. within the next couple of minutes). Another approach would be to have a handler on failed HTTP calls, where calls failing due to expired tokens are retried automatically after performing a token refresh. The first approach is simpler to get right.
On the client side, would it suffice to set a timeout function to occur in, lets say, X minutes (1 minute before the token is supposed to expire), that will then refresh the token? Having a poll seems wasteful.
I would set this timeout on load when the initial token is validated, and then set another timeout once we refresh the token again in case the user is consistently on
Sure, that would work. It comes down to personal preference.
I would personally have a function run once a minute or so to check the lifetime of the currently active refresh token, and perform some action if necessary. That way I only need to create and schedule this function once, and be done with it. On paper, it's more wasteful, but in the grand scheme of things I feel the performance impact is negligible. It's dumb, but I often prefer dumb solutions.
Your method with creating and scheduling some function call in the future based on the current lifetime of the refresh token is definitely more elegant, though you would have to take into account scenarios where the token and its lifetime may change during the runtime of your app (e.g. a user logging out and back in, or some other reason why a token may become invalidated). You may end up with having state for both your refresh-token, and your future refresh timeout function. That said, none of this makes your approach any less valid.
You need to be prepared that any request returns unauthorized (expired token) - then you use your refresh token to request a new access token and retry the request.
This can be done gracefully, usually it's handled by an interceptor in your client code. So the user will never have to refresh the page/resubmit a form due to his expired token.
To expand: Refresh tokens are really meant for a three actor system, and some people seem to fuck it up and send the refresh token all the way to the end user.
Tokens are the moral equivalent of expiring video URLs. They stop someone from having permanent access to an asset by having seen it once. Like scraping bots, people with expired subscriptions. Tokens stop someone from having permanent access to your account by having eavesdropped once. Or finding your lost device.
What is supposed to happen is the service the user talks to finds the refresh token at login time, sends a token to the user, and then the user can talk to any of your 100 endpoints directly or indirectly by sending them the token and then they forward it on to each other for any recursive service calls. My last company had big problems, but they had audit trails right due to propagating tokens, and correlation ids right at a time when you still had to prod people do add them.
They are meant to reduce some of the latency and complexity involved with fanout. And particularly things like JWT where the token can bear PII about the user and thus avoid a query to the user table for every single request in the chain.
This article is pretty light on the content
[deleted]
Most of these articles on substack are shallow.
So… it’s the framework for a web article?
… I’ll see myself out
I just want to point out that OAuth2 by itself is NOT authentication, it's delegated authorization. OIDC adds the openid scope and a number of other things that together turn oauth2 into delegated authentication.
Dead internet theory, ftw.
Also, these concepts are not distinct, an oAuth server can issue JWT as its access / refresh tokens just as easily as some random gibberish.
What does dead internet theory have to with oauth2? Not picking a fight with you it's just I was surprised by the sudden mention of it
The blogspam article, not oauth2.
Oh no wonder. I recently got into open id auth using krakend and keycloak so i thought this article would be helpful. Guess not huh. Thanks though
The various RFC on this are helpful.
This article uses a lot of words to not really say anything at all and was probably written by AI
Java revisited has been spamming low quality affiliated linked articles since the start of time in every language, library and framework possible.
Its an example of the internet proliferating garbage.. e.g dying.
Substack seems to be mostly AI generated content, or stuff written by people who know even less than AI.
OAuth2 is just a workflow. It includes authentication in its workflow to grant authorization. Stating that it’s authorization and not authentication is a bit disingenuous. You cannot really have Authorization without Authentication happening per the spec so you’re quite wrong.
OIDC is just a flavored implementation of OAuth2 workflow that calls out specific components to use. There can be other implementations of the OAuth2 workflow that are just as secure that don’t conform to OIDC.
OAuth2 has nothing to do authentication. RFC 6749 section 3.1 is quite clear on this point:
Saying OAuth 2 does authentication is like saying HTTP does encryption, you can bolt TLS on top, but HTTP itself is not an encryption protocol.
You’re obviously misunderstanding that the requirement “to identify the resource owner” is part of the spec. The specific manner in which that is done is left to the implementation (and thus outside the spec).
OAuth2 is just a workflow for performing authorization using an external IDP. The workflow requires an identity authentication step, hence the the presence of authentication is implicit. If your OAuth solution it does not contain the idp step - then it’s not OAuth, period. The spec does not need tell you how to perform authentication outside of how to exchange tokens via some well known endpoints. As one of the co-authors, the type of authentication performed is left undefined because it was recognized that each use case had different needs in establishing and proving identity. Hence you can have valid OAuth workflow with and without MFA, utilize Passkeys, and solutions not invented yet. My point is that Authentication is a required and implicit step in OAuth 2.0. Stating that it excludes authentication is just incorrect. OIDC is just a specific implementation of OAuth2 which provides a very specific authentication step. There can be an infinite number of OAuth2 implementations - all must have a specific authentication step otherwise they are NOT OAuth2.
Mommy and daddy are fighting
I just want to point out that Linux is NOT an operating system, it's a free component of a GNU system. GNU adds the corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX.
I just want to point out that Linux exists without GNU, and in fact there are popular distros like Alpine that have no GNu in them.
I just want to point out that honey is not vegan.
I just want to point out that it's not ethical non-monogamy without informed consent.
I just want to point out that if it doesn't come from the Pilates region of Aspen, it's merely sparkling yoga.
Any other totally unrelated axes you need to grind? Democratic socialism? Vaccines?
I was pointing out that he is being needlessly pedantic by comparing his comment to the infamous Linux/GNU copypasta. Rather than pasting the entire thing here, I edited it down to match his exact phrasing, but with Linux terms instead of OAuth.
https://www.reddit.com/r/copypasta/comments/63oudw/gnu_linux/
Lol! My bad! I will not hide my shame by deleting my comment. You have bested me in fair combat as the more highly skilled smart-ass, and I doff my fedora to you, good sir.
Pastas only work in full. Otherwise you run into Poe's Law issues too quickly.
If people are interested in more, GNU has an in-depth explanation.
https://www.gnu.org/gnu/linux-and-gnu.en.html
Technically, saying that many people use the GNU System isn't fully accurate. The GNU project makes the distinction of calling it the GNU/Linux system.
linux contains some proprietary portions, which while free from a monetary perspective, are at odds with the free use principles GNU has been after.
The GNU project itself has the Hurd kernel, which never really went into mainstream use, and also maintain a variety of Linux (linux-libre) that is stripped of the parts they disagree with.
Same for JWTs, its authz, authn is offloaded to the IdP
I don't think I agree?
Help me out here: I get an API request with a JWT, I use the JWKS to verify the JWT is from a legitimate source, I have proven you are authentically who you claim to be. I haven't verified you're authorized to use this API call though. I need to check your privileges for that, but what I do know is you did successfully complete a login because the JWT signature is an authentic one, ergo you are authentically who your JWT claims.
Am I misunderstanding the terms here?
As I understand, you are not verifying the authentification of the user, the IdP did. Then you verify the IdP gave the user an authorization (via the token) to call your API.
Verifying the token signature is not the same as verifying the user's authN. The token only says he was authorized to make such and such requests on behalf of this user, not that the token holder is the person that was authenticated.
Verifying the user's identity requires password, 2FA and other measures to validate the correct identity. Once it's done they're issued a token saying they can interact with the app as that user.
In your example, depending on your endpoint security checks, just having a valid token is enough to authorize the request. Sometimes you need to verify the privileges (eg. admin action), sometimes you don't (edit your own profile). In both cases, you are authorizing the request based on the token. You did not verify the identity of the user (because you trust your IdP signature).
I wouldn't put it that way. Even if your service is authorizing the request because of the token, that decision was not made by the token issuer - thus the issuer and the token itself are not responsible for authorization. You, as the service, made that authorization decision after verifying the user's authentic identity (though ultimately the identity itself doesn't matter to you). I think this is pedantic to the point of being reductive, same as saying, "verifying a user's password is not proof of identity, it's authorization, because it only says the person is authorized to know the user's password not that it's actually them".
I do understand what you mean by
but still, that's the point of delegating authentication to another authority - at some point you have to trust the IdP signature. And it doesn't make sense to me to say that "my service isn't involved in authenticating the user, someone else does that". The caller is passing you a token and you are resolving it to a trusted identity. That's authentication. The fact that you trusted somebody else to receive the user's password, etc. just means that you've centralized part of the authentication process, not that you skip it entirely.
Well, the JWT is supposed to contain claims. Those claims already certify what the user is authorized to do.
Potentially, not everyone puts those claims in their JWT, so yes I agree a JWT may also declare an authentic privilege set, but generally it will definitely have an authentic identity, whether the privileges are bundled in the JWT or not
It should have been named OAutho2 to avoid confusion imo
Such a bad article.
Can someone explain why bearer tokens are more secure than basic auth?
It's a token normally returned from a POST request to an Auth endpoint where the username and password are in the body of the request. The response to that request is normally something like /
You then use that token (which will have an expiry though it doesn't always come with a refresh token so it can be longer lived) in an API request to get data from another API endpoint.
i.e. GET /api/users/1/account-balance
Where the header contains
(Then it's obviously up to the backend to make sure the token is 1. Valid and 2. The requesting user is allowed to see user id 1's account balance.)
So if a token leaks, technically they aren't seeing credentials that would issue them new tokens endlessly, they'd only see a token that almost certainly has a shorter lifespan with no knowledge of how to get a new one (as the username and password aren't part of the request header).
On a related note, I never understood why bearer tokens and the
Authorizationheader are a thing when cookies already exist.Bearer tokens are meant for other clients, the ones that necessarily a browser.
As with everyting in this world, we had devs who had to reinvent the wheel so they came up with using Authorization header with Bearer tokens, in frontend code - for no valid reason at all - apart from, perhaps, having no clue that cookies existed.
So I can hit the API with curl.
It would be nice if curl had the ability to send cookies but alas it has been missing this very basic HTTP functionality since its first release back in 1917.
What are you talking about?! curl has supported HTTP cookies for ages.
And even if dedicated support didn’t exist, you could always manually send and receive cookies via the corresponding HTTP header fields.
Why do you think curl doesn't support sending cookies? It can definitely send cookies.
Any client which isn’t a browser that needs to authenticate. An example may be a mobile app.
The Authorization header was created before the Cookie header. Having these headers separate allows a web server to do authentication before cookies are even handled. It also doesn't need to split the cookie to determine if authentication is happening.
I think it came from micro services. Hitting the auth service on each page request is "expensive", so the solution is to issue tokens that are valid for some period of time, to avoid network roundtrips to the auth service. I've never really seen any explanation either but that's the only one that makes sense to me.
But the issued tokens can be sent as cookies...they don't need to be sent as bearer tokens.
Tokens are often short lived (e.g. a few hours) or can easily be revoked and regenerated as needed. Tokens are generated by an authorized user (e.g. the user themselves or an admin). On the authorization side, fine-grain permissions can be associated with the token to reduce what it can do so if it is compromised there's less "surface area" of attack.
Basic auth is a bigger risk as it's sending your username and password (or sometimes a user-level token). If someone were to get this, they may have a bigger attack area depending on user permissions, able to change the password, and if you reuse passwords for other accounts, those could be compromised as well.
Basic auth contains your literal credentials in plaintext format (base64, but that's just encoding). If someone intercepts that, they now have your username and password. Tokens have expiration date, so if someone intercepts your token, they can only use it for a short while.
OAuth generated tokens will (typically) have an expiration date but it's not inherent to bearer tokens. Most of the services that I interact with that use bearer tokens/api keys do not have expiration
Bearer tokens don't do anything by themselves, they're just an arbitrary string you put auth information into.
They're "more secure" than basic auth when they're used to implement a better auth scheme, like OIDC.
In one of your other comments you express skepticism about API keys, but that's because API keys are, as an auth scheme, not much better than basic auth. Their main upside is that they usually have a narrower scope. They're still long-lived creds passed as plaintext though.
The rest has been explained by other commenters.
In addition to what others have stated, basic auth just tells the endpoint who you are. But a bearer token while being short lived also can restrict what you are allowed to do. So user jsmith can send a bearer token that only allows certain permissions to https://somesketchyservice.com/notverytrustworthy and if the untrusted api decides to turn around and try to use your bearer token to do other things on your behalf they would likely fail because that bearer token you sent it doesn't have permission to do anything outside what it was scoped to do. If you had sent a username password then you're basically handing the keys to the castle to anyone that needs to provide services to you...
What the other guy is trying to say is that it has built-in rotation - but you can implement that in basic auth too so IMO actual advantage comes from standardization and not having to reimplement things that libraries can do for you (for both server and clients) - less room for your own mistakes. Ofc this only makes sense in the context of oauth (ie bearer being oauth and basic meaning non-oauth)- in the abstract both basic and bearer are just different notations for potentially the same thing.
Yeah, I think a lot of people conflate bearer tokens with oauth when they're not the same thing. An oauth authentication transaction can provide you with a bearer token which has a pre-defined expiration (and I completely agree is more secure) but I work with a lot of services (HubSpot, Salesforce, ServiceNow) where I'm issued a permanent bearer token as part of the user-application definition, which to me is functionally equivalent to basic authentication in that it's something that gets passed with every request and does not expire.
It doesn't help that oauth coopted being a token, rather than cookie terminology, when it carries session.
Oauth/OIDC isn't the only way to use bearer tokens that's better than basic auth, it's just become such a common practice that people conflate it with JWT and token-based auth in general.
Bearer tokens are short lived, doesn't have stored credentials, and extremely difficult to spoof assuming service is securely signing and verifying tokens.
I think you're thinking of a JWT, which is a subset of bearer tokens in general
Would have been better as AI generated content
Side question:
Does this explain why so many websites and services do not keep you logged in if you don't access them for longer than a day or two? Perhaps because everyone uses access and refresh tokens now, and not accessing the service for a little while means your refresh token has expired?
If yes, then this is an artifact of modern authorization that drives me crazy -- it feels like I can't stay logged into anything any longer! And I'm skeptical that the security benefits of this practice outweigh the bad user experience. Why not let me stay logged in, like the websites of yesteryear? Is there really a solid security justification for it?
In all fairness, this isn't the fault of the authentication method being used. The expiration time of access and refresh tokens are determined by the team developing the software you are using. It's not an inherent limitation of access/refresh tokens. The websites you use could choose to use refresh tokens with an expiration time of months, if they wanted to.
Yes, shorter lifetimes of authentication tokens (cookies, tokens, etc.) reduce the risk of session hijacking attacks.
I honestly don't understand why session hijacking is the justification for this. Is there any way to hijack my session that doesn't involve malicious software running directly on my computer? In that case there's a lot more to be worried about, and the malicious software doesn't even need an active session to hijack an account. And if I were regularly using the account, as is generally the case with anything of great importance like, say, a Google or Amazon account, then the session hasn't expired and it could still theoretically be hijacked!
Certainly. For example: physical attack vectors. Your device could get lost and/or stolen, a malicious individual could access your machine while you are temporarily not present and steal your authentication state from your drive or browser. You could sell your device without ensuring that no data may be recovered from disk after a factory reset, after which someone may be able to recover this information.
Another class of attacks would be improper data storage and/or leaks on devices you have no access to. A period of improper logging configuration in one system that accidentally stores user credentials in a logging database for a period of time for instance.
It depends. Malware that can intercept keystrokes could bypass the need to steal active session state like cookies or tokens. Though modern security guidelines encourage the use of more than one-factor in order to partially mitigate these vectors. Of note in this case is that here too the period a two factor code is valid is time limited.
At the risk of sounding like ChatGPT: you're right. Session lifetime management and expiration is one layer of mitgation/defense that helps mitigate certain attack vectors, but are not infallible or a silver bullet of any kind. They are one security measure of your entire defense in depth strategy.
😆
I think basically my point is that, if I had the choice to sacrifice that little bit of security, and I don't really think it's that much extra security, for the convenience and better user experience of not getting logged out, then I would do that. And I wish sites gave us that choice.
And if someone gains physical access to my device, then it's the same situation as malware: everything is compromised. It doesn't matter if there are active sessions; they have access to my email (and possibly even my phone number!) and therefore can hijack any account of mine that they want. In that situation my course is the same regardless of whether the sessions are active or not: revoke email access immediately, revoke all active sessions, change every password, pray!
I agree with you, so much if this is hyperbole, and big ego. Just let the user stay logged in, it's not a big deal.
Sort of. It's still possible to have a long session, but it's no longer the default, so less sites offer it. I would consider it risky if there is any payment or personal information in the profile or any messaging capabilities.
The bad user experience could be due to the site design, or it could be from your own habits not updating over time. If you are still typing website passwords in 2025, then you need to update your habits. Logging in should be 2 extra clicks.
I'm not manually typing in passwords -- I have a password manager. But it's death by a thousand cuts. Having to log into one website is fine. Having to do it multiple times a day every day because every website behaves this way now is wearisome.
I am still fuzzy on refresh tokens. I understand on load, we can validate a token the client has in the browser. However, how do we refresh a token? Do we realize client side, and request a new token with the said refresh token? What do I do if in the middle of their session their token expires when doing a `get posts` call? How am I supposed to "update" the access token without disrupting the user?
There's many ways. One approach would be to have some sort of background process automatically do a token refresh whenever the current token is close to expiration (e.g. within the next couple of minutes). Another approach would be to have a handler on failed HTTP calls, where calls failing due to expired tokens are retried automatically after performing a token refresh. The first approach is simpler to get right.
On the client side, would it suffice to set a timeout function to occur in, lets say, X minutes (1 minute before the token is supposed to expire), that will then refresh the token? Having a poll seems wasteful.
I would set this timeout on load when the initial token is validated, and then set another timeout once we refresh the token again in case the user is consistently on
Sure, that would work. It comes down to personal preference.
I would personally have a function run once a minute or so to check the lifetime of the currently active refresh token, and perform some action if necessary. That way I only need to create and schedule this function once, and be done with it. On paper, it's more wasteful, but in the grand scheme of things I feel the performance impact is negligible. It's dumb, but I often prefer dumb solutions.
Your method with creating and scheduling some function call in the future based on the current lifetime of the refresh token is definitely more elegant, though you would have to take into account scenarios where the token and its lifetime may change during the runtime of your app (e.g. a user logging out and back in, or some other reason why a token may become invalidated). You may end up with having state for both your refresh-token, and your future refresh timeout function. That said, none of this makes your approach any less valid.
Thank you for the insight! I just rolled up auth by myself for the first time, and want to make sure I do things right (or the best I can). Thank you!
You need to be prepared that any request returns unauthorized (expired token) - then you use your refresh token to request a new access token and retry the request.
This can be done gracefully, usually it's handled by an interceptor in your client code. So the user will never have to refresh the page/resubmit a form due to his expired token.
To expand: Refresh tokens are really meant for a three actor system, and some people seem to fuck it up and send the refresh token all the way to the end user.
Tokens are the moral equivalent of expiring video URLs. They stop someone from having permanent access to an asset by having seen it once. Like scraping bots, people with expired subscriptions. Tokens stop someone from having permanent access to your account by having eavesdropped once. Or finding your lost device.
What is supposed to happen is the service the user talks to finds the refresh token at login time, sends a token to the user, and then the user can talk to any of your 100 endpoints directly or indirectly by sending them the token and then they forward it on to each other for any recursive service calls. My last company had big problems, but they had audit trails right due to propagating tokens, and correlation ids right at a time when you still had to prod people do add them.
They are meant to reduce some of the latency and complexity involved with fanout. And particularly things like JWT where the token can bear PII about the user and thus avoid a query to the user table for every single request in the chain.
there's probably an xkcd comic which explains this more concisely in 3 ms paint pictures
I’ve just built a system that has two types: machines get an APIKey; humans get a PassKey. That’s all you need, kids.
Zoom in to the image for 439 €. Yeah, okay.
/edit: Holy… It's not just on the first, it's on every image!
What a garbage article.
OAuth2 is not for authentication, it is for authorization. There are some providers that add an authentication to it (like OpenID).
RFC 6749 is even titled "The OAuth 2.0 Authorization Framework"
OAuth2 is an authorization specification, not authentication.
/remindme 1 day
Good post, thank
welc