In late 2018, Facebook’s engineering team found a security flaw that affected around 50 million accounts. It began with a feature called "View As," which let users see how their profile looked to others. However, this feature had a serious vulnerability. Attackers found they could use it to steal Facebook access tokens.
An access token is like a digital key that lets an app access an API. It tells the API that the token holder is allowed to do certain things. In this case, attackers used stolen access tokens to take over Facebook accounts, possibly accessing personal messages, photos, and other sensitive information.
Can you believe it? Almost 90 million Facebook users were affected by a breach that compromised access tokens to the platform!😱
In a more recent example, the popular AI platform Hugging Face reported a security breach on its Spaces platform, a community repository for AI apps. Hackers accessed authentication secrets, possibly compromising user data. And this happened just a few days ago.
Read more about the security breach here.
With the above two incidents, you’ve probably understood the importance of access tokens and the implications of them getting exposed. In today's digital world, managing these tokens well is essential to protect sensitive data such as personal information, credit card details, government issues documents, etc and maintain user trust.
Until now, we’ve used the word "Token" quite a bit - but what exactly is it? Let's understand tokens and their types.
Let's talk about Tokens 🔑
Tokens are pieces of data containing information to identify a user and determine if they are allowed to perform certain actions. In short, tokens help application systems with authorization and authentication.
Before understanding the various types of security tokens, let’s do a quick recap on Authorization & Authentication, and how the two differ. We’ll try and understand it with a fun example.
What is Authentication?
Authentication is the process of verifying who a user or device is. During this process, the user or device provides some proof, called an authentication factor, to confirm their identity. Is that confusing? Let’s try to make sense of it using an everyday example.
Imagine you’re going to the bank to withdraw some money. The clerk will ask for your ID to verify that you are exactly who you say you are. Similarly, when you buy a flight ticket, you need to show your passport to prove you are the person who bought the ticket before boarding the plane. These are two real-life examples of authentication, where your identity is confirmed.
When we talk about authentication in the software realm, the core concept is the same as the two examples we discussed above. However, the methods are different. Instead of using a physical government issues identification, you’d use tokens to validate the identity
What is Authorization?
In contrast to authentication, authorization is about checking what resources users or devices can access and what actions they can perform.
For example, when you buy a ticket for a show, the venue doesn't care about your identity. They just want to know if you are allowed to attend the show. To prove this, you use a ticket instead of an ID or passport.
In internet-based software apps, a common way to handle authorization is by using things called tokens. Once a user is logged in, the app starts focusing on what the user can do. This is where a token comes in—it holds details about what the user is allowed to do based on their identity. The system then uses this token to decide whether to grant or deny access to resources.
So, you see, authentication and authorization can sometimes get mixed up, which can be confusing.
But here's the key thing: authentication comes before authorization, but not the other way around.
While proving who you are might be enough to get access to something (that's authorization), just having permission doesn't always tell you who someone is.
So, about those tokens—in the world of web authentication and authorization, you might have heard the term "Bearer token." But what does it mean? How does it work? And why is "Bearer" in front of the token?
What's the deal with Bearer Tokens? 🙄
Bearer tokens are a way to show what kind of token is being used for logging in and getting access to resources within your system. They're often used with OAuth 2.0 and other token-based systems.
When you log in, you get a token from the server. This token proves you're logged in and lets you access protected parts of a web server. You usually put the Bearer token in the “Authorization” header of an HTTP request.
To show that the token is a “Bearer” type, you put the word "Bearer" before the actual token in the “Authorization” header.
Here's what the “Authorization” header looks like with a Bearer token:
Authorization: Bearer <token>
In this example, <token>
is the actual token given to the client by the authentication server. The web server that gets the request can then check and validate the token. If the token is valid and authorized, it grants access to the requested resource.
Moving on, what kind of token should we use for Authentication or Authorization?
"Let's secure this API call with a token. Should I go with the ID token or the access token? The ID token looks better to me. I mean, if I know who the user is, I can make better authorization choices, right?"
This is not the correct way to choose a particular token for your use case. Choices based on your intuition may sound good, but what looks intuitive is not always correct. Using the wrong token can result in your solution being insecure.
Let’s take a closer look at these two types of tokens to better understand their role.
Show your ID - ID token? 🪪
An ID token is an artifact that proves that the user has been authenticated. It was introduced by OpenID Connect (OIDC), an open standard for authentication used by many identity providers such as Google & Facebook.
Consider the following diagram:
Here, a user with their browser authenticates against an OpenID provider and gets access to a web application. The result of that login process, based on OpenID Connect, is the ID token, which is sent to the app as proof that the user is authenticated.
This gives a basic idea of what an ID token is: proof that the user is authenticated.
An ID token is encoded as a JSON Web Token (JWT), a standard format that lets your app easily check its content, ensure it comes from the right issuer, and verify that no one has tampered with it. If you want to learn more about JWT, check out this article.
An ID token something looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vbXktZG9tYWluLmF1dGgwLmNvbSIsInN1YiI6ImF1dGgwfDEyMzQ1NiIsImF1ZCI6IjEyMzRhYmNkZWYiLCJleHAiOjEzMTEyODE5NzAsImlhdCI6MTMxMTI4MDk3MCwibmFtZSI6IkphbmUgRG9lIiwiZ2l2ZW5fbmFtZSI6IkphbmUiLCJmYW1pbHlfbmFtZSI6IkRvZSJ9.bql-jxlG9B_bielkqOnjTY9Di9FillFb6IMQINXoYsweyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vbXktZG9tYWluLmF1dGgwLmNvbSIsInN1YiI6ImF1dGgwfDEyMzQ1NiIsImF1ZCI6IjEyMzRhYmNkZWYiLCJleHAiOjEzMTEyODE5NzAsImlhdCI6MTMxMTI4MDk3MCwibmFtZSI6IkphbmUgRG9lIiwiZ2l2ZW5fbmFtZSI6IkphbmUiLCJmYW1pbHlfbmFtZSI6IkRvZSJ9.bql-jxlG9B_bielkqOnjTY9Di9FillFb6IMQINXoYsw
Of course, this isn't readable to the human eye, so you'll need to decode it to see what's inside the JWT.
You can use the debugger at jwt.io to do this.
Need access - Access Token? 🔓
Now that you know what an ID token is, let’s try to understand what an access token is.
Let's start by depicting a scenario where the access token is used:
Using the above diagram, imagine that a client application wants to access a resource. This resource can be anything like an API, database or something else that's protected from unauthorized access. The other two elements in the diagram are the user, who is the owner of the resource, and the authorization server. In this setup, the access token is what lets the client application access the user's resource. It's given out by the authorization server after the user successfully logs in and gives their consent.
The access token lets a client application access a specific resource to do specific actions on behalf of the user. This is called a delegated authorization scenario: the user lets a client application access a resource for them. For example, you can let your LinkedIn app access Twitter’s API to cross-post on both social platforms. Remember, you only allow LinkedIn to post on Twitter for you. You don't let it delete posts, change your profile, or do other things.
In short, the API needs to use that token to let the client application do what it needs to do with the resource.
This is the content of a decoded access token that follows the JWT format:
{
"iss": "https://YOUR_DOMAIN/",
"sub": "auth0|123456",
"aud": [
"my-api-identifier",
"https://YOUR_DOMAIN/userinfo"
],
"azp": "YOUR_CLIENT_ID",
"exp": 1489179954,
"iat": 1489143954,
"scope": "openid profile email address phone read:appointments"
}
Alright! Now you know what an ID token and an access token are.
The access token is a bearer token, meaning anyone who holds it can use it. It acts as a credential to access protected resources. If malicious users steal access tokens, they can access protected resources by presenting those tokens to the server.
To reduce this risk, it's crucial to have security strategies. One method is to create access tokens with a short lifespan, valid for only a few hours or days.
When an access token expires, the client application can either prompt the user to log in again or use a refresh token to get a new access token from the authorization server.
Before we understand what is refresh token, an important concept is a short-lived token.
Short-lived tokens - great for security; bad for DX 👎🏼
Short-lived tokens, as the name suggests, have a limited validity period. This limitation is crucial for several reasons:
Reduced Risk of Compromise: If a token is leaked, its short lifespan ensures that it quickly becomes useless to an attacker.
Automatic Rotation: Systems can be designed to automatically issue new tokens at regular intervals, ensuring continuous security without manual intervention.
Enhanced Traceability: Short-lived tokens can be logged and monitored more effectively, providing better insights into system access and usage patterns.
Refresh tokens - Bridge between Security & DX 🌉
As mentioned, for security reasons, access tokens might only be valid for a short time. Once they expire, client apps can use a refresh token to refresh the access token. A refresh token is simply a credential that lets a client app get new access tokens without asking the user to log in again.
Keeping Refresh Tokens Secure ✅
Short-lived access tokens boost our app's security, but there's a downside: when they expire, users need to log in again to get a new one. This frequent re-authentication can make your app seem annoying or hard to use, even if it's for their protection.
A refresh token can help you balance security with usability. Since refresh tokens usually last longer, you can use them to get new access tokens after the short-lived ones expire.
However, since refresh tokens are also bearer tokens, we need a plan to limit their use if they ever get leaked or compromised. Anyone holding the refresh tokens can get new access tokens whenever they want. "They" could be legitimate users or attackers.
To drive home the point about securing the refresh token, the recent Cloudflare breach underscores the importance of robust token management. When attackers exploited stolen credentials to access internal systems, the value of having a secure, centralized token management system became evident. By implementing a Security Token Service(STS), organizations can better protect their resources against unauthorized access and minimize the risk of breaches.
This is where Tremolo security's OpenUnisoncomes into the picture.
Implementing Security Tokens with Open Unison
How does OpenUnison, a security token service, make token management secure?
OpenUnison works with GitOps systems like Argo CD and Flux CD to keep your tokens safe. When you're using these systems, it's super important to handle tokens for accessing repositories and clusters securely. OpenUnison does this by:
Issuing Short-Lived Tokens: Tokens are created with a short lifespan, so they don't stay around too long and reduce the risk of exposure.
Token Validation: Tokens are checked to make sure they're being used by the right people. For example, if a pod using a token is deleted, the token stops working, which helps prevent unauthorized access.
Token Rotation: Tokens are automatically changed regularly, so you're not stuck with static credentials. This ongoing rotation boosts security and lowers the chance of token leaks.
What happens when you start doing cross-cluster stuff where you have multiple clusters?
In environments with multiple clusters, Open Unison helps establish a common trust boundary by issuing tokens that are valid across clusters, facilitating secure communication and management.
Key Things OpenUnison Does for Securing Tokens 👀
Token Expiration: Make sure tokens don't last too long to cut down on the risk of unauthorized access.
Automatic Rotation: Set up systems to automatically issue and rotate tokens so you don't have to rely on static credentials.
Robust Validation: Use tools like OpenUnison to check tokens and make sure only the right people are using them.
Monitoring and Logging: Keep logs of token usage to watch for any unusual activity.
If you want to see some of this in action, check out this video of OpenUnison in action & interesting conversation with Marc, CTO @ Tremolo Security, Marino, and Aakansha. Also, feel free to follow the docs via GitHub!
Finally, we did a live stream on Namespace as a Service which was also an extension to security tokens. Catch the recording here!!!
Cheers and thanks for reading 😊!