Try to clear the main Auth concepts from higher perspective.
Term Overview
OAuth vs OpenID vs OIDC
- OpenID is based on a simple idea: a user authenticates with an identity provider (IDP), who then provides the user with a unique identifier (called an OpenID). This identifier can then be used to authenticate the user with any website that supports OpenID.
- OAuth(Open Authorization), Originally designed to for applications to get access to APIs. grants access to Other resources via Access Tokens.
- OpenID Connect (OIDC) is an identity layer built on top of the OAuth 2.0 framework. It allows third-party applications to verify the identity of the end-user and to obtain basic user profile information. OIDC uses JWTs, which you can obtain using flows conforming to the OAuth 2.0 specifications. Simply saying, it adds an additional token called ID Token.
Anology
Let’s understand that like this: a Guest check at a hotel reception with ID card, then reception give him a digit key which can unlock a hotel room, or visit gym, swiming pool, etc. Hotel room lock just accept the key and don’t care who use it. Guest is User, Reception is OpenID IDP(Authentication), digit card is Access token. Now, there is a apecial service, kid care, which need digit key, and User information to show up as well. OAuth can do nothing about this, but OIDC can do it!
OIDC and JWT
Each time you need to log in to a website using OIDC, you are redirected to your OpenID site where you log in, and then taken back to the website. For example, if you chose to sign in to Auth0 using your Google account then you used OIDC. Once you successfully authenticate with Google and authorize Auth0 to access your information, Google sends information back to Auth0 about the user and the authentication performed. This information is returned in a JWT. You’ll receive an access token and if requested, an ID token.
The OIDC specification defines a set of standard claims for JWT. The set of standard claims include name, email, gender, birth date, and so on. However, if you want to capture information about a user and there currently isn’t a standard claim that best reflects this piece of information, you can create custom claims and add them to your tokens.
How is OIDC different from OpenID2.0?
OIDC has many architectural similarities to OpenID 2.0, and in fact the protocols solve a very similar set of problems. However, OpenID 2.0 used XML and a custom message signature scheme that in practice sometimes proved difficult for developers to get right, with the effect that OpenID 2.0 implementations would sometimes mysteriously refuse to interoperate. OAuth 2.0, the substrate for OpenID Connect, outsources the necessary encryption to the Web’s built-in TLS (also called HTTPS or SSL) infrastructure, which is universally implemented on both client and server platforms. OpenID Connect uses standard JWT data structures when signatures are required. This makes OpenID Connect dramatically easier for developers to implement, and in practice has resulted in much better interoperability.
More concrete way to understand the concepts
- Authentication = Identifying user
- Authorization = Accessing APIs
JWT Overview
JSON Web Token (JWT) defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed.
- JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
- Although JWT can be encrypted to also provide secrecy between parties, It will focus on signed tokens.
- Because most of JWTS are not encrypted, you can read them.
- It need to be used with HTTPS connection.
TWO common usage scenarios
- Authorization: This is the most common scenario for using JWT. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. Single Sign On is a feature that widely uses JWT nowadays, because of its small overhead and its ability to be easily used across different domains.
- Information Exchange: JSON Web Tokens are a good way of securely transmitting information between parties. Because JWTs can be signed — for example, using public/private key pairs — you can be sure the senders are who they say they are. Additionally, as the signature is calculated using the header and the payload, you can also verify that the content hasn’t been tampered with.
JWT structure
Three parts separated by dots (.), which are:
- Header
- Payload
- Signature
Like this:

Header and Payload are just plain text that get encoded, but not encrypted. So everyone can read them. JWT just focus on signed.
Client-side/Stateless Sessions
The so-called stateless sessions are in fact nothing more than client-side data. Most of the time sessions need only be signed. In other words, there is no security or privacy concern when data stored in them is read by third parties. client-side data can be suffered Security attack like, Signature Stripping, CSRF, XSS. Use JWT propertly can protect. For example adding CSRF mitigation techniques. Sometime a certain balance between client-side data and database lookups in the backend is necessary.
One Concrete Example
Here copy a example to show how to use JWT.
For example we will make a simple shopping application. The user’s shopping cart will be stored client-side. In this example, there are multiple JWTs present. Our shopping cart will be one of them.
- One JWT for the ID token, a token that carries the user’s profile information, useful for the UI.
- One JWT for interacting with the API backend (the access token).
- One JWT for our client-side state: the shopping cart. Here’s how the shopping cart looks when decoded:
{ "items": [ 0, 2, 4 ], "iat": 1493139659, "exp": 1493143259 }
Each item is identified by a numeric ID. The encoded and signed JWT looks like:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpdGVtcyI6WzAsMiw0XSwiaWF0IjoxNDkzMTM5NjU5LCJleHAiOjE0OTMxNDMyNTl9. 932ZxtZzy1qhLXs932hd04J58Ihbg5_g_rIrj-Z16Js
To render the items in the cart, the frontend only needs to retrieve it from its cookie:
function populateCart() { const cartElem = $('#cart'); cartElem.empty(); const cartToken = Cookies.get('cart'); if(!cartToken) { return; } const cart = jwt_decode(cartToken).items; cart.forEach(itemId => { const name = items.find(item => item.id == itemId).name; cartElem.append(`<li>${name}</li>`); }); }
The actual checks are performed by the backend. All JWTs are verified. Here is the backend check for the validity of the cart JWT implemented as an Express middleware:
function cartValidator(req, res, next) { if(!req.cookies.cart) { req.cart = { items: [] }; } else { try { req.cart = { items: jwt.verify(req.cookies.cart, process.env.AUTH0_CART_SECRET, cartVerifyJwtOptions).items }; } catch(e) { req.cart = { items: [] }; } } next(); }
When items are added, the backend constructs a new JWT with the new item in it and a new signature:
app.get('/protected/add_item', idValidator, cartValidator, (req, res) => { req.cart.items.push(parseInt(req.query.id)); const newCart = jwt.sign(req.cart, process.env.AUTH0_CART_SECRET, cartSignJwtOptions); res.cookie('cart', newCart, { maxAge: 1000 * 60 * 60 }); res.end(); console.log(`Item ID ${req.query.id} added to cart.`); });
Note that locations prefixed by /protected are also protected by the API access token. This is setup using express-jwt:
app.use('/protected', expressJwt({ secret: jwksClient.expressJwtSecret(jwksOpts), issuer: process.env.AUTH0_API_ISSUER, audience: process.env.AUTH0_API_AUDIENCE, requestProperty: 'accessToken', getToken: req => { return req.cookies['access_token']; } }));
In other words, the
/protected/add_item
endpoint must first pass the access token validation step before validating the cart. One token validates access (authorization) to the API and the other token validates the integrity of the client side data (the cart). The access token and the ID token are assigned by Auth0 to our application. This requires setting up a client and an API endpoint using the Auth0 dashboard. These are then retrieved using the Auth0 JavaScript library, called by our frontend://Auth0 Client ID const clientId = "t42WY87weXzepAdUlwMiHYRBQj9qWVAT"; //Auth0 Domain const domain = "speyrott.auth0.com"; const auth0 = new window.auth0.WebAuth({ domain: domain, clientID: clientId, audience: '/protected', scope: 'openid profile purchase', responseType: 'id_token token', redirectUri: 'http://localhost:3000/auth/', responseMode: 'form_post' }); //(...) $('#login-button').on('click', function(event) { auth0.authorize(); });
The audience claim must match the one setup for your API endpoint using the Auth0 dashboard. The Auth0 authentication and authorization server displays a login screen with our settings and then redirects back to our application at a specific path with the tokens we requested. These are handled by our backend which simply sets them as cookies:
app.post('/auth', (req, res) => { res.cookie('access_token', req.body.access_token, { httpOnly: true, maxAge: req.body.expires_in * 1000 }); res.cookie('id_token', req.body.id_token, { maxAge: req.body.expires_in * 1000 }); res.redirect('/'); });
You can Implement CSRF mitigation techniques on the top of this example.
OAuth2 Overview
OAuth Concept
OAuth, or Open Authorization, is a standard that allows users to authorize apps to access their data and resources without sharing their login credentials. OAuth uses access tokens to grant temporary access to third parties. These tokens contain information about the user and the resource, as well as specific rules for data sharing.
There are different OAuth Flow for defferent app types:
- Single-page app (SPA)
- Web app
- Web API
- Mobile and native apps
- Service, daemon, script
OAuth Benefits
OAuth allows users to:
- Share specific data with an application while keeping their usernames, passwords, and other information private
- Use one-click logins to identify themselves to a web service without having to enter their username and password every time
What is OAuth Apps
You need to Creating an OAuth Apps first before you can use OAuth.
OAuth apps are applications that use the OAuth protocol to allow users to grant third-party access to their data without sharing their password.
For Example: Vercel provide Server platform for developer to deploy their application which code can be store in GitHub. If you want to allow Vercel to access GitHub to deploy your application, you need to install an OAuth app in your Repo. After the OAuth installation, Vercel can access that Reop.
MobilePrinter must first register a new app with the service.
- You must register a redirect URI to be used for redirecting users to for web server.
- You will get Client ID and Secret.
Authorization process
Let’s say, you are developing a MobilePrinter Website App which using OAuth process. This App can help users print photo in Other server, like Google photos.
There are 4 Roles:
- The Third-Party Application, “Client”, MobilePrinter Website App
- The API: “Resource Server”, Visiting Google photos
- The Authorization Server: Google
- The User: “Resource Owner”
MobilePrinter Website use Client ID and Secret communicate with the authorization server, (Google).
- Create a “Log In” link sending the user to:
https://authorization-server.com/auth?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos&state=1234zyx
- The user sees the authorization prompt (Allow or Deny) from authorization-server.
- If the user clicks “Allow” the authorization-service redirects the user back to your site with an authorization code:
https://example-app.com/cb?code=AUTH_CODE_HERE&state=1234zyx
- To Get an Access Token, Your server should exchanges the authorization code for an access token by making a POST request to the authorization server’s token endpoint:
POST https://api.authorization-server.com/token grant_type=authorization_code& code=AUTH_CODE_HERE& redirect_uri=REDIRECT_URI& client_id=CLIENT_ID& client_secret=CLIENT_SECRET
- The server replies with an access token and expiration time
{ "access_token":"RsT5OjbzRn430zqMLgV3Ia", "expires_in":3600 }
Session Management
Session management involves tracking and managing a user’s interaction with the application over time, ensuring that their authenticated state is preserved across different parts of the application.
This prevents the need for repeated logins, enhancing both security and user convenience. There are two primary methods used for session management:
- cookie-based (storing session data on the User Browser, data should be encrypted)
- database sessions(storing session data on the server)
JWT Sessions vs Database Sessions
- JWT refer to as stateless. Dataase is the opposite, stateful.
- Both need cookie (http-only). Database session use cookie for SessionID and JWT use cookies to store more information.
- JWT need bigger and more cookies; But reduce the interact between server and database.
- Database Sessions can be safer.
- JWT also good for Single Sign On.
Authentication Solutions
- There are many authentication solutions. Like, Auth0, Clerk, Kinde etc.
- You can add these solutions to your application.
- They all support Modern authentication strategies, like OAuth/OpenID Connect (OIDC), Credentials-based login (Email + Password), Passwordless/Token-based authentication.
FAQ
- Common use case for JWT?
- How JWT implement authorization?
- What is Cross-Site Request Forgery (CSRF)?
- What is Cross-Site Scripting (XSS)?
- How is OIDC different from OpenID2.0?
What is Cross-Site Request Forgery (CSRF)?
Unlike cross-site scripting (XSS), which exploits the trust a user has for a particular site, CSRF exploits the trust that a site has in a user’s browser. In a CSRF attack, an innocent end user is tricked by an attacker into submitting a web request that they did not intend. This may cause actions to be performed on the website that can include inadvertent client or server data leakage, change of session state, or manipulation of an end user’s account.
What is Cross-Site Scripting (XSS)
Cross-site scripting (XSS) attacks attempt to inject JavaScript in trusted sites. Injected JavaScript can then steal tokens from cookies and local storage. If an access token is leaked before it expires, a malicious user could use it to access protected resources.
- Don’t use localStorage, cause JS can read it.
- use cookie with ‘http-only’ setting.
How JWT implement authorization
JWTs are self-contained, all the necessary information is there, reducing the need of going back and forward to the database. JWTs can container Authorization information.
References
- jwt.io
- OAuth2 simplified
- jwt-handbook-v0_14_2.pdf