OpenID Connect vs OAuth 2.0: What Developers Actually Need to Know
OAuth 2.0 and OpenID Connect are often used together, but they solve different problems. Learn the practical difference between authorization, authentication, access tokens, ID tokens, scopes, and user identity.
BlitzWare Engineering - 2026-06-28
OAuth 2.0 and OpenID Connect are often mentioned together.
That makes sense because they are related.
But they are not the same thing.
The simplest way to remember the difference is this:
OAuth 2.0 is for authorization.
OpenID Connect is for authentication.
OAuth 2.0 answers:
Can this application access this API?
OpenID Connect answers:
Who is the user that signed in?
In real applications, you usually need both.
If you’re building a SaaS dashboard, mobile app, API platform, developer portal, internal tool, or single page application, this distinction matters. Misunderstanding it can lead to broken login flows, insecure API authorization, incorrect token validation, and confusing architecture decisions.
This guide explains the practical difference between OAuth 2.0 and OpenID Connect from a developer’s point of view.
The 30-second summary
| Technology | What it is | What it solves |
|---|---|---|
| OAuth 2.0 | Authorization framework | Lets applications access protected resources |
| OpenID Connect | Identity layer on top of OAuth 2.0 | Lets applications authenticate users and receive identity information |
OAuth 2.0 gives you access tokens.
OpenID Connect adds ID tokens.
OAuth 2.0 is about access.
OpenID Connect is about identity.
If your application needs to call an API, you need OAuth 2.0.
If your application needs to know who the user is, you likely need OpenID Connect.
Most modern login systems use OpenID Connect on top of OAuth 2.0.
A simple analogy
Imagine an office building.
OAuth 2.0 is like an access badge.
The badge says:
This person or application can enter Room A and Room B.
It does not necessarily explain who the person is in detail. It is mainly about access to resources.
OpenID Connect is like checking someone’s identity at the front desk.
The front desk says:
This person is Jane Developer.
Their email is [email protected].
They authenticated successfully.
OAuth 2.0 gives access.
OpenID Connect gives identity.
In a real system, you often use both:
Authenticate the user with OpenID Connect.
Authorize API access with OAuth 2.0.
What OAuth 2.0 actually does
OAuth 2.0 is an authorization framework.
It lets an application obtain limited access to a protected resource.
A protected resource is usually an API.
For example:
A frontend application wants to call your backend API.
A mobile app wants to read a user's profile.
A third-party integration wants access to a customer's workspace.
A CLI tool wants to manage resources through your API.
OAuth 2.0 defines how the application gets an access token.
The application then sends that access token to the API.
Example API request:
GET /api/projects
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
The API validates the access token and decides whether the request is allowed.
OAuth 2.0 focuses on questions like:
- Which client is requesting access?
- Which resource is being accessed?
- Which scopes were granted?
- How long should the token be valid?
- Can this token be used for this API?
- Should this request be allowed?
OAuth 2.0 does not define a standard way to log users in.
OAuth 2.0 does not define a standard identity token.
OAuth 2.0 does not define a standard user profile format.
That is where OpenID Connect comes in.
What OpenID Connect actually does
OpenID Connect, often shortened to OIDC, is an identity layer built on top of OAuth 2.0.
It adds a standardized way to authenticate users and communicate information about them.
The most important thing OpenID Connect adds is the ID token.
An ID token is usually a JWT that tells the client application who authenticated.
Example ID token payload:
{
"iss": "https://auth.example.com",
"sub": "user_123",
"aud": "client_456",
"exp": 1793200000,
"iat": 1793196400,
"email": "[email protected]",
"email_verified": true,
"name": "Jane Developer"
}
This token is meant for the client application.
It helps the application answer:
Who signed in?
When did they authenticate?
Which authorization server authenticated them?
Which client was this identity token issued for?
What basic identity claims are available?
OpenID Connect also defines standard scopes such as:
openid
profile
email
phone
address
The openid scope is what tells the authorization server that the application is requesting OpenID Connect behavior.
Without openid, you are usually doing OAuth 2.0 only.
With openid, you are asking for authentication and identity information.
OAuth 2.0 vs OpenID Connect in one flow
A modern login flow often uses both OAuth 2.0 and OpenID Connect.
Example authorization request:
https://auth.example.com/oauth/authorize?
response_type=code&
client_id=client_123&
redirect_uri=https://app.example.com/callback&
scope=openid profile email api.read&
state=random_state&
code_challenge=pkce_challenge&
code_challenge_method=S256
Notice the scope:
openid profile email api.read
This includes both identity and API access.
| Scope | Meaning |
|---|---|
openid |
Request OpenID Connect authentication |
profile |
Request basic profile claims |
email |
Request email-related claims |
api.read |
Request API access |
After the user authenticates, the application exchanges an authorization code for tokens.
Example token response:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 900,
"scope": "openid profile email api.read"
}
This response may include:
| Token | Comes from | Used for |
|---|---|---|
| Access token | OAuth 2.0 | Calling APIs |
| ID token | OpenID Connect | Identifying the authenticated user |
| Refresh token | OAuth 2.0 extension behavior | Getting new access tokens |
The access token goes to your API.
The ID token is for your application.
Do not treat them as interchangeable.
Access token vs ID token
This is one of the most important distinctions.
Access token
An access token is used to access an API.
Example:
GET /api/projects
Authorization: Bearer <access_token>
The API validates the access token.
The API should check things like:
- Signature
- Issuer
- Audience
- Expiration
- Scopes
- Token type
- Subject
- Client ID
The access token answers:
Is this request allowed to access this API?
ID token
An ID token is used by the client application to understand the authenticated user.
Example:
{
"sub": "user_123",
"email": "[email protected]",
"name": "Jane Developer"
}
The ID token answers:
Who signed in?
The ID token should usually not be sent to your API as the authorization credential.
Your API should receive an access token.
Your frontend or application client receives and validates the ID token for login state and identity purposes.
Why this distinction matters
If you use the wrong token in the wrong place, your architecture becomes weaker.
Bad pattern:
Frontend logs in with OIDC.
Frontend receives ID token.
Frontend sends ID token to API.
API accepts ID token as proof of API access.
This is a common mistake.
An ID token is not designed to represent API permissions.
A better pattern:
Frontend logs in with OIDC.
Frontend receives ID token for user identity.
Frontend receives access token for API access.
Frontend sends access token to API.
API validates access token and scopes.
This keeps identity and authorization separate.
That separation makes your system easier to secure, debug, and scale.
What about “Login with Google”?
When developers say “OAuth login,” they often mean “login with Google,” “login with Discord,” or “login with GitHub.”
Technically, many modern social login flows are OpenID Connect or OAuth-based flows.
For example, when an application offers “Sign in with Google,” the application often uses OpenID Connect to get an ID token that proves who the user is.
The user experience is:
Click "Sign in with Google"
Authenticate with Google
Return to the application
Application knows who the user is
From the user’s perspective, it is login.
From the protocol perspective, OpenID Connect is usually the part that standardizes identity.
OAuth 2.0 may still be involved underneath because OpenID Connect is built on OAuth 2.0.
That is why people often mix the terms.
The practical developer rule is:
If you need user login, use OpenID Connect.
If you need API access, use OAuth 2.0 access tokens.
If you need both, use OpenID Connect with OAuth scopes.
Token comparison
| Token | Standardized by | Audience | Main purpose |
|---|---|---|---|
| Access token | OAuth 2.0 | API / resource server | Authorize API access |
| ID token | OpenID Connect | Client application | Prove user authentication |
| Refresh token | OAuth 2.0 | Client / authorization server | Obtain new access tokens |
The most common mistake is sending the ID token to the API and treating it as an access token.
The second most common mistake is using an access token as the application’s user profile.
Keep them separate.
The role of scopes
Scopes are often used in both OAuth 2.0 and OpenID Connect.
But they mean different things depending on what you request.
OAuth API scopes
OAuth scopes describe API permissions.
Examples:
projects:read
projects:write
billing:read
users:manage
These are useful for backend authorization.
Example:
This token can read projects but cannot delete them.
OpenID Connect scopes
OpenID Connect scopes describe identity information being requested.
Examples:
openid
profile
email
phone
address
These are useful for login and user identity.
Example:
This application wants to know the user's email address.
A combined request might look like this:
openid profile email projects:read projects:write
That means:
Authenticate the user.
Return basic identity information.
Grant access to read and write projects.
The openid scope is special
The openid scope is what turns an OAuth authorization request into an OpenID Connect request.
Without it:
scope=api.read
You are asking for OAuth API access.
With it:
scope=openid profile email api.read
You are asking for OpenID Connect authentication plus OAuth API access.
If you expect an ID token but forget the openid scope, your authorization server may not return one.
If your app only needs API access and not user identity, you may not need OpenID Connect at all.
But if your app needs login, the openid scope is usually required.
The UserInfo endpoint
OpenID Connect also defines a UserInfo endpoint.
The client can call it with an access token to retrieve user claims.
Example:
GET /userinfo
Authorization: Bearer <access_token>
Example response:
{
"sub": "user_123",
"email": "[email protected]",
"email_verified": true,
"name": "Jane Developer"
}
The UserInfo endpoint is useful when:
- You do not want many claims inside the ID token.
- You want to fetch profile information separately.
- You want a standard way to retrieve user claims.
- The client needs updated user profile data.
The ID token proves authentication.
The UserInfo endpoint can provide additional user claims.
Real-world example: SaaS dashboard
Imagine you are building a SaaS dashboard.
Users log in and manage projects.
You need to know who the user is.
You also need to call your backend API.
A good flow:
1. User clicks "Log in".
2. App redirects to authorization server.
3. User authenticates.
4. App receives authorization code.
5. App exchanges code for tokens.
6. App receives ID token and access token.
7. App uses ID token to understand login identity.
8. App uses access token to call the API.
9. API validates access token and checks scopes.
Example ID token:
{
"sub": "user_123",
"email": "[email protected]",
"name": "Jane Developer",
"aud": "client_abc"
}
Example access token:
{
"sub": "user_123",
"aud": "https://api.example.com",
"scope": "projects:read projects:write",
"client_id": "client_abc"
}
The ID token is for the app.
The access token is for the API.
The sub value may identify the same user, but the tokens serve different purposes.
Real-world example: machine-to-machine API access
Now imagine there is no user.
A backend service needs to call another backend service.
Example:
Billing service needs to call Reporting API.
In this case, OpenID Connect is usually not needed because there is no user to authenticate.
You need OAuth 2.0 client credentials.
Flow:
1. Service authenticates as a client.
2. Authorization server issues access token.
3. Service calls API with access token.
4. API validates token and scopes.
Example token payload:
{
"iss": "https://auth.example.com",
"sub": "client_billing_service",
"aud": "https://reporting-api.example.com",
"scope": "reports:write",
"client_id": "billing_service"
}
No ID token is required.
OAuth 2.0 alone is enough.
Real-world example: third-party integration
Imagine your product allows customers to connect a third-party app.
The third-party app needs access to the customer’s resources.
Example:
A customer grants an external analytics tool access to read project data.
This is classic OAuth 2.0.
The important question is not just “who is the user?”
The important question is:
Did the customer authorize this client to access this resource with these scopes?
The result is an access token with limited permissions.
Example:
{
"sub": "user_123",
"client_id": "external_analytics_app",
"aud": "https://api.example.com",
"scope": "projects:read analytics:read",
"exp": 1793200000
}
OpenID Connect may be used to authenticate the user during the flow, but OAuth 2.0 is what handles delegated API access.
Authentication vs authorization
The words are similar, but the difference matters.
Authentication means:
Who are you?
Authorization means:
What are you allowed to access?
OpenID Connect helps with authentication.
OAuth 2.0 helps with authorization.
A user can be authenticated but not authorized.
Example:
Jane is logged in.
Jane is not allowed to access the billing settings.
A service can be authorized without representing a human user.
Example:
The deployment service can write deployment logs.
No human user is involved.
Good systems separate these concepts clearly.
Should your app use OAuth 2.0, OpenID Connect, or both?
Use this decision table.
| Your use case | What you need |
|---|---|
| Users log into your app | OpenID Connect |
| Your frontend calls your API | OAuth 2.0 access tokens |
| Your app needs both login and API access | OpenID Connect + OAuth 2.0 |
| Service-to-service API access | OAuth 2.0 client credentials |
| Third-party integrations | OAuth 2.0 authorization |
| Social login | Usually OpenID Connect or provider-specific OAuth |
| User profile claims | OpenID Connect |
| API permissions and scopes | OAuth 2.0 |
Most SaaS applications need both.
Most APIs need OAuth 2.0.
Most login experiences should use OpenID Connect.
How access tokens should be validated
Your API should validate access tokens strictly.
For JWT access tokens, check:
- Signature
- Issuer
- Audience
- Expiration
- Not-before time
- Algorithm
- Key ID
- Token type
- Scopes
- Subject
- Client ID
- Revocation status if supported
Example Express middleware:
import type { Request, Response, NextFunction } from "express";
import { createRemoteJWKSet, jwtVerify } from "jose";
const issuer = "https://auth.example.com";
const audience = "https://api.example.com";
const jwks = createRemoteJWKSet(new URL(`${issuer}/.well-known/jwks.json`));
export async function authenticateApiRequest(
req: Request,
res: Response,
next: NextFunction
) {
const header = req.headers.authorization;
if (!header?.startsWith("Bearer ")) {
return res.status(401).json({
error: "Missing access token.",
});
}
const token = header.slice("Bearer ".length);
try {
const { payload } = await jwtVerify(token, jwks, {
issuer,
audience,
algorithms: ["RS256", "ES256"],
clockTolerance: "30s",
});
req.auth = {
subject: payload.sub,
clientId: payload.client_id,
scope: typeof payload.scope === "string" ? payload.scope : "",
};
next();
} catch {
return res.status(401).json({
error: "Invalid or expired access token.",
});
}
}
Then enforce scopes:
export function requireScope(requiredScope: string) {
return (req: Request, res: Response, next: NextFunction) => {
const scopes = new Set((req.auth?.scope ?? "").split(" ").filter(Boolean));
if (!scopes.has(requiredScope)) {
return res.status(403).json({
error: "Insufficient permissions.",
});
}
next();
};
}
Usage:
app.get(
"/api/projects",
authenticateApiRequest,
requireScope("projects:read"),
async (req, res) => {
res.json({
projects: [],
});
}
);
Your API should not trust the frontend.
Your API should not accept a token just because it can be decoded.
Your API should validate the access token every time.
How ID tokens should be validated
A client application that receives an ID token should also validate it.
For an ID token, check:
- Signature
- Issuer
- Audience
- Expiration
- Nonce, when used
- Subject
- Authorized party, when relevant
- Authentication time, when required
The most important difference is the audience.
For an ID token, the audience is usually the client application.
For an access token, the audience is usually the API.
Example ID token:
{
"iss": "https://auth.example.com",
"sub": "user_123",
"aud": "client_abc",
"exp": 1793200000,
"iat": 1793196400,
"nonce": "random_nonce"
}
Example access token:
{
"iss": "https://auth.example.com",
"sub": "user_123",
"aud": "https://api.example.com",
"exp": 1793200000,
"iat": 1793196400,
"scope": "projects:read"
}
If your API expects audience:
https://api.example.com
it should reject a token whose audience is:
client_abc
That is one reason APIs should not accept ID tokens as access tokens.
Common misconceptions
Misconception 1: OAuth 2.0 is a login protocol
OAuth 2.0 alone is not a complete login protocol.
It is an authorization framework.
You can build login-like behavior with OAuth 2.0, and many providers historically did, but OpenID Connect was created to standardize authentication and identity on top of OAuth 2.0.
For modern applications, use OpenID Connect when you need login.
Misconception 2: If I have an access token, I know who the user is
Maybe, but not always.
An access token may represent:
- A user
- A service account
- A machine client
- A delegated authorization
- A technical integration
The sub claim can identify a subject, but the token’s main purpose is API access.
If your application needs a standardized user identity for login, use OpenID Connect.
Misconception 3: ID tokens are for APIs
ID tokens are for client applications.
APIs should normally receive access tokens.
If an API accepts ID tokens, it can accidentally bypass scope checks, audience validation, and resource-specific authorization rules.
Use the right token for the right job.
Misconception 4: OpenID Connect replaces OAuth 2.0
OpenID Connect does not replace OAuth 2.0.
It extends it.
OpenID Connect uses OAuth 2.0 flows and adds identity features.
That is why a modern login flow can return both an ID token and an access token.
Misconception 5: JWT means OpenID Connect
JWT is a token format.
OAuth 2.0 access tokens can be JWTs.
OpenID Connect ID tokens are usually JWTs.
But JWT itself is not OAuth and not OpenID Connect.
A JWT can be used for many different purposes.
Always validate what kind of JWT it is and what it is meant for.
Common security mistakes
Avoid these mistakes:
- Sending ID tokens to APIs as access tokens.
- Accepting tokens without validating the audience.
- Accepting tokens without validating the issuer.
- Decoding JWTs without verifying signatures.
- Using OAuth 2.0 alone as a login protocol when OpenID Connect is needed.
- Forgetting the
openidscope. - Treating frontend checks as authorization.
- Giving access tokens overly broad scopes.
- Putting too much personal data inside tokens.
- Logging tokens.
- Using long-lived access tokens in browser apps.
- Shipping client secrets in frontend code.
- Using the Implicit Flow for new browser-based applications.
- Ignoring PKCE for public clients.
- Confusing authentication with authorization.
Most OAuth and OpenID Connect bugs come from unclear boundaries.
Know which token is for which audience and which purpose.
Practical architecture patterns
SPA with API backend
Use:
OpenID Connect for login
OAuth 2.0 access tokens for API calls
Authorization Code Flow with PKCE
The SPA gets an ID token for identity and an access token for the API.
The API validates the access token.
Server-rendered web application
Use:
OpenID Connect for login
Server-side session for browser state
OAuth 2.0 access tokens if the server calls APIs
The backend can store tokens server-side.
The browser gets a secure session cookie.
Mobile application
Use:
OpenID Connect for login
OAuth 2.0 access tokens for APIs
Authorization Code Flow with PKCE
System browser for authentication
Avoid embedded web views for login.
Use the platform browser or secure authentication session APIs.
Machine-to-machine service
Use:
OAuth 2.0 client credentials
Access tokens
No OpenID Connect unless a user identity is involved
There is usually no ID token because there is no human user.
Third-party integration platform
Use:
OAuth 2.0 authorization flows
Granular scopes
Consent screens
Access token validation
Refresh token rotation where needed
OpenID Connect may be used for user login, but OAuth 2.0 is the core of delegated access.
How to explain this to your team
Use this simple rule:
OAuth 2.0 lets apps access APIs.
OpenID Connect lets apps know who logged in.
Then add:
Access tokens go to APIs.
ID tokens go to clients.
And finally:
Scopes describe permissions.
Claims describe identity and token metadata.
This mental model prevents many design mistakes.
Developer checklist
Use this checklist when designing authentication and authorization.
If users log in
- Use OpenID Connect.
- Request the
openidscope. - Validate the ID token.
- Use nonce where appropriate.
- Treat the ID token as identity information for the client.
- Do not use the ID token as the API credential.
If your app calls an API
- Use OAuth 2.0 access tokens.
- Validate access tokens at the API.
- Check issuer, audience, signature, expiration, and scopes.
- Use short-lived access tokens.
- Do not rely on frontend-only authorization checks.
If your app needs both
- Use OpenID Connect plus OAuth scopes.
- Request identity scopes and API scopes.
- Use the ID token for login state.
- Use the access token for API calls.
- Keep token audiences separate.
If there is no user
- Use OAuth 2.0 client credentials.
- Issue access tokens to machine clients.
- Use scopes for service permissions.
- Do not use OpenID Connect unless you need identity.
OpenID Connect vs OAuth 2.0 comparison table
| Question | OAuth 2.0 | OpenID Connect |
|---|---|---|
| What problem does it solve? | Authorization | Authentication |
| Main token | Access token | ID token |
| Used by | APIs and resource servers | Client applications |
| Answers | What can access what? | Who is the user? |
| Standard user identity? | No | Yes |
| Standard login layer? | No | Yes |
| Built on OAuth 2.0? | Base framework | Yes |
| Uses scopes? | Yes | Yes |
| Useful for APIs? | Yes | Indirectly |
| Useful for login? | Not by itself | Yes |
How BlitzWare helps
BlitzWare is designed to help developers implement authentication and authorization without rebuilding the same security-sensitive infrastructure from scratch.
With BlitzWare, you can build systems that need:
- OAuth 2.0 authorization
- User authentication
- Social login
- API authentication
- User management
- MFA
- RBAC
- Database connections
- Customizable hosted authentication pages
- Authentication analytics
- License-key authentication
- Device locking
For teams building SaaS products, APIs, dashboards, internal tools, and developer platforms, the goal is to keep the hard authentication logic centralized while giving developers the flexibility they need.
You can learn more on the OAuth Authentication product page, Direct API Authentication product page, and Database Connections product page.
Final thoughts
OAuth 2.0 and OpenID Connect are closely related, but they are not interchangeable.
OAuth 2.0 is about authorization.
OpenID Connect is about authentication.
Access tokens are for APIs.
ID tokens are for clients.
Scopes describe access.
Claims describe identity and token metadata.
If you remember only one thing, remember this:
Use OpenID Connect to log users in.
Use OAuth 2.0 access tokens to call APIs.
Once that distinction is clear, the rest of the architecture becomes much easier to reason about.
You will know which tokens to request, where to send them, how to validate them, and which security checks belong in the frontend versus the backend.
That clarity is what keeps authentication systems secure, maintainable, and understandable as your product grows.