ToolSura
    ToolSura
    HomeTools
    Blog
    ToolSuraPrivacy-First Tools

    Free utilities that run in your browser. No trackers, no accounts, no uploads.

    All Systems Operational

    Product

    • Free Online Tools
    • Contact
    • FAQs
    • About

    Legal

    • Privacy Policy
    • Cookie Policy
    • Terms & Conditions

    Resources

    • Blog
    • Brand
    • Help

    Social Links

    • Bluesky
    • Mastodon
    • X
    • Product Hunt
    • GitHub
    • LinkedIn
    • DEV.to
    • YouTube

    © 2026 ToolSura. Free tools that run in your browser.

    Remote-First / Based in India

    Technical Manifesto

    Private • Client-Side • No Uploads

    ToolSura on Nick Launches
    Browser-Native
    Privacy-First
    Skip to main content
    Toolsura
    OAuth
    H
    Hiro Tanabe

    Where OAuth ends and OpenID Connect begins

    August 21, 2026 · 11 min read

    OAuth vs OpenID Connect explained: authentication versus authorization, the 5-step PKCE flow, an ID-token checklist, and a real RS256 token, fully decoded.

    OAuth and OpenID Connect mapped side by side: authorization versus authentication flows
    OAuth and OpenID Connect mapped side by side: authorization versus authentication flows

    By ToolSura DevTools Team, Senior Engineers · View profile

    Key takeaways
    • OAuth 2.0 answers what an app may access; OpenID Connect answers who the user is
    • OIDC is a thin identity layer built on top of OAuth 2.0, not a competing protocol
    • Adding the openid scope value is what flips a plain OAuth request into an OIDC login
    • The ID token, a JWS-signed JWT, is the artifact that turns delegated access into authentication
    • Code flow with PKCE is the modern default, and OAuth 2.1 will require it outright

    The OAuth vs OpenID Connect confusion comes down to one word: authentication. OAuth 2.0, standardized as RFC 6749 in October 2012, lets an application obtain scoped access to resources without ever establishing who is present. OpenID Connect, finalized in February 2014, bolts the identity layer on top. A single login request usually exercises both at once, which is exactly why engineers keep mixing them up. This guide draws the line, walks the PKCE flow step by step, decodes a real ID token, and tracks where the in-progress OAuth 2.1 profile leaves both protocols.

    The one-sentence difference

    OAuth 2.0 is not an authentication protocol. It is an authorization framework: as RFC 6749 frames it, it “enables a third-party application to obtain limited access to an HTTP service,” with the user's password never reaching the client. OpenID Connect 1.0 describes itself as “a simple identity layer on top of the OAuth 2.0 protocol”: it keeps the entire OAuth machinery and adds the pieces that tell your application who just logged in.

    The confusion is structural, not accidental. OIDC requests look exactly like OAuth requests because they are OAuth requests, with one scope value and one extra token added to carry identity. As Justin Richer explains in the canonical oauth.net analysis, a client presenting an access token is its authorized presenter, not its audience: the token says nothing about whether the user is still present, or who they were. That single distinction drives every design decision in this article.

    A useful mental model: OAuth issues keys to a room; OpenID Connect also checks your badge at the door. An app can hold broad access tokens yet know nothing reliable about the person who approved them, until OIDC enters the picture.

    What plain OAuth 2.0 provides

    The framework itself is RFC 6749, The OAuth 2.0 Authorization Framework, published October 2012. It defines how a client obtains an access token through flows called grants, and in the authorization code case, as section 1.3.1 puts it, “the resource owner's credentials are never shared with the client.” A companion document, RFC 6750, separately specifies how bearer access tokens travel inside HTTP requests; it defines token usage, not the framework itself. The token carries scopes such as read:orders, and the resource server enforces them on every call. Nothing in that exchange guarantees the client learns the user's name, email, or any stable identifier. OAuth deliberately stayed out of the identity business, which is precisely the gap OIDC fills.

    The common OAuth grants and where they fit
    GrantTypical use today
    Authorization code + PKCEWeb apps, SPAs, mobile: the default choice
    Client credentialsMachine-to-machine calls with no user present
    Refresh token grantExchanging a stored refresh token for fresh access without re-prompting
    ImplicitDeprecated; legacy browsers only
    Resource owner passwordDeprecated; legacy migrations only

    Those deprecation rows come straight from the standards. RFC 9700, the OAuth 2.0 Security Best Current Practice published January 2025, states that the resource owner password grant “MUST NOT be used” and that the implicit flow “SHOULD NOT” be shipped at all. It also expects PKCE far beyond the native apps that RFC 7636, from September 2015, originally had in mind, a shift the step-by-step section below walks through.

    What OpenID Connect adds

    OIDC Core, final since February 2014 with errata set 2 published December 2023, adds three pieces to plain OAuth: the ID token, a JWT signed by the provider whose claims name the authenticated user; the userinfo endpoint, which returns the same profile as plain JSON; and discovery, a well-known URL that publishes every endpoint and key a client needs. Our JWT internals guide covers the token format itself in depth. The two mechanics that matter most are the scope that activates all of it, and the document that wires it together.

    The openid scope: the switch that flips OAuth into OIDC

    One scope value converts an OAuth request into an OIDC one. Section 3.1.2.1 of the Core spec is unambiguous: “OpenID Connect requests MUST contain the openid scope value,” and “if the openid scope value is not present, the behavior is entirely unspecified.” Without it, no ID token is guaranteed and no identity claims are owed. Other scopes then control which claims ship: Google's implementation maps email to the email and email_verified claims, and profile to name, picture, given_name, family_name, and locale. One rule from the same documentation saves migrations later: use the sub claim, never the email address, as your permanent user identifier, because sub is stable and email addresses change.

    The discovery endpoint: clients that configure themselves

    Every conforming provider publishes a JSON document at /.well-known/openid-configuration, standardized in the OIDC Discovery specification. It lists the authorization endpoint, the token endpoint, the userinfo endpoint, the supported scopes and claim types, and a jwks_uri pointing at the provider's public signing keys. When the provider rotates keys, verifiers pick up the new set from the same URL with zero configuration changes; that is also how the kid field inside a token header resolves to an actual key at verification time. Paste your own provider's document into the JSON formatter to see exactly which scopes and claims it supports before writing client code.

    A real ID token, inspected

    Theory helps, but a token you can decode yourself settles the question faster. We generated the RS256-signed ID token below from scratch during research, using nothing but Python and openssl, and every claim in it is real:

    eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0yMDI2LTA4In0.eyJpc3MiOiJodHRwczovL2F1dGguc2hvcGRlbW8uZXhhbXBsZSIsInN1YiI6InVzZXItNzMxNSIsImF1ZCI6InNob3BkZW1vLXdlYiIsIm5hbWUiOiJTYW0gUml2ZXJhIiwiZW1haWwiOiJzYW1Ac2hvcGRlbW8uZXhhbXBsZSIsImlhdCI6MTc4NzM0NTQ2MCwiZXhwIjoxNzg3MzQ5MDYwfQ.TihF3GABdV_sY4SFeglETdpwuMHaxgL0TI_jLu4rA2uBjiOrqR30D4PcIx5sLZXHCgdpUBxDyToKsN2rd3Wlv8bopAQwNhmVLZxx-k6jyYHK-R2Gi2qDaSwgCHoaZuNCQQqMCkBS9_OPva_aCG0NIWb_CjLP5j3KP-hz9HqK5CIwrHQNKL-7ay9K6TTJE60pamKqUOAk9wieC9gBojqVQiQtN0yYUchyz-Mtq3kIl76a_pfsa3A6M-Aud83Xj9Dm8OGmC9Fuvl5Km8-4N0kNG1nrFGIe4SRX7Kt8zpfQ7KWKWJPPhPAXTeZ0Qvp7KS2vZiEQ_x-r5_MOCIfvlvLYcw

    Decoding the first two segments reveals the identity payload riding inside an otherwise ordinary JWT: issuer https://auth.shopdemo.example, subject user-7315, audience shopdemo-web, profile claims, and one-hour validity. Note the header's kid field naming which key signed it, a rotation mechanism the JWK specification formalizes; production providers publish the matching public set at the jwks_uri from their discovery document, so verifiers stay current. Paste any real ID token into the JWT decoder to run the same inspection on tokens you encounter.

    ID token vs access token: which goes where

    The two tokens answer different questions and are addressed to different audiences, and swapping them is the most damaging mistake in this space. An ID token is addressed to your client: its aud claim names your client_id, and it exists so your application can establish a session. An access token is addressed to the resource server; your client is merely its authorized presenter, the exact distinction Justin Richer draws in the oauth.net analysis cited above.

    The handling rules follow directly. Send the access token in the Authorization header when calling an API. Never send an ID token there: no conforming API accepts it as a credential, because a resource server cannot verify claims minted for a different audience. Consume the ID token inside the client, validate it, create the session, and do not forward it to third-party services. When you need a stable user identifier, take sub from the ID token, never the email address.

    In our experience, few mainstream libraries stop you from passing the wrong token; the failure surfaces weeks later, as one service quietly trusting claims a different audience never verified.

    Authorization code flow with PKCE, step by step

    RFC 7636, published September 2015, designed PKCE specifically against authorization-code interception, and RFC 8252, the native-app best current practice, made it mandatory for those clients in 2017. The authorization code flow with PKCE proceeds in five steps:

    1. The application generates a random code_verifier and derives a code_challenge from it; the PKCE generator produces a valid pair in one click
    2. The browser opens the provider's authorization URL carrying the challenge, the client id, the redirect URI, and your scopes, including openid when login is the goal
    3. The user authenticates and consents; the provider redirects back with a one-time code
    4. The application exchanges the code plus the original verifier at the token endpoint
    5. The provider verifies the verifier against the challenge and returns tokens: the access token always, the ID token when openid was requested

    To watch the whole exchange live, our OAuth demo playground runs this exact flow against a test provider and shows both tokens arriving in the same response.

    Validating an ID token: the five checks

    ID-token validation is its own checklist, and skipping any line of it reintroduces the vulnerabilities the design prevents. RFC 9700 reiterates the same discipline for every token type:

    1. Verify the signature against the provider's published keys for the matching kid
    2. Confirm iss matches your configured provider exactly, scheme and trailing slash included
    3. Confirm aud names your client, rejecting tokens minted for anyone else
    4. Check exp against the current clock with small skew tolerance
    5. If a nonce was sent, confirm it returns unchanged inside the token

    Two flow parameters defend different legs of the exchange, so keep them separate: state binds the redirect back to your outgoing request, blocking CSRF and mixed-up sessions, while nonce binds the ID token to your authentication request, blocking replay. A random UUID from the UUID generator serves for either. RFC 9700 even permits a nonce as an alternative mitigation to PKCE for confidential OIDC clients, which shows how closely the two protections overlap.

    Signing algorithms and the psychic-signature lesson

    OIDC Core requires ID tokens to be signed using JWS, but leaves room in algorithm choice, and that room has produced an entire attack class. RFC 7519, the original JWT specification, made none and HS256 the only two MUST-implement algorithms, a decision RFC 8725, the JWT best current practice, later diagnosed as the root cause of alg-confusion attacks.

    Two variants dominate. With alg:none, a library that trusts the token header happily “validates” an unsigned forgery an attacker fully controls. With RS256-to-HS256 confusion, the attacker flips the header to HS256 and signs the token using the provider's RSA public key as the HMAC secret; a verifier that re-reads the algorithm from the header then checks the forgery with the very key it published. The BCP's fix is one line: each key MUST be used with exactly one algorithm, pinned on the verifier's side, never taken from the attacker-controlled header.

    Then there is CVE-2022-21449, the “psychic signatures” bug Neil Madden disclosed in an April 2022 post. Java 15 through 18 did not check that the ECDSA signature values r and s were non-zero, so an all-zeros signature validated for any message; any JWT library that relies on the JVM's built-in ECDSA verification would accept a forged ES256 ID token on an unpatched JVM. Oracle shipped the fix on April 19, 2022, and NVD scored the flaw 7.5. The lesson generalizes: verification code is security-critical, and trusting library defaults is not a validation strategy. Pin your algorithms and test against forged tokens.

    OAuth vs OpenID Connect side by side

    With the mechanics covered, the comparison compresses to six rows:

    OAuth 2.0 versus OpenID Connect
    AspectOAuth 2.0OpenID Connect
    Core questionWhat may the app access?Who is the user?
    Primary artifactAccess token (opaque or JWT)ID token (always a JWT)
    Token audienceThe resource server (your API)The client (your application)
    StandardRFC 6749 and friendsOIDC Core, Discovery, more
    Standalone useAPI access, machine authLogin on top of OAuth
    User identity claimsNone definedsub, email, profile, etc.

    Mistakes that keep appearing

    • Treating an access token as proof of identity; it proves a scope grant, not who is present, the exact confusion Richer's analysis warns enables token-injection logins
    • Sending an ID token to an API, or an access token to a session store; each token has exactly one audience
    • Skipping ID token validation: issuer, audience, expiry, and signature all need checking, as RFC 9700 reiterates for every token type
    • Accepting the alg field straight from the token header, the alg-confusion family RFC 8725 documents
    • Using the email address as the user identifier instead of the stable sub claim
    • Shipping implicit flow out of habit when code-plus-PKCE is strictly safer per RFC 9700

    The first mistake deserves emphasis because it survives in production systems: accepting any valid access token from anyone as a login is the confusion this article exists to prevent. The verification rules for the JWTs involved mirror what our token decoding guide demonstrates hands-on.

    Two protocols, one handshake

    Once you see the layering, the OAuth vs OpenID Connect question answers itself: OIDC is OAuth wearing a badge checker. Use plain OAuth for delegated API access between machines and services; add OIDC whenever a human logs in and the application must know reliably who arrived. In practice the two ship together: one authorization code exchange returns both tokens, which is the norm rather than an exotic configuration.

    The rules keep consolidating. The OAuth 2.1 draft, revision 15 as of March 2, 2026, mandates PKCE for every client, omits the implicit and password grants entirely, and carries a December 2026 milestone for IESG submission, all while staying wire-compatible with deployed OAuth 2.0. The editors' overview frames it as the same protocol, restated rather than replaced. RFC 9700 already enforces most of it as best current practice today.

    Looking further ahead, passkeys are replacing the password leg inside the provider's login screen, but they change how the user authenticates, not how the handshake speaks: OIDC still delivers the identity. Our passkeys vs passwords comparison and passkeys primer cover that layer. Meanwhile the playbook stands: request code flow with PKCE, validate every ID token against issuer, audience, and clock, and let discovery wire the pieces together.

    Last updated: August 2026 | Published: August 2026 | About ToolSura · Contact

    Hiro Tanabe

    Written by

    Hiro Tanabe

    I take one token and walk through it in order, because the failure modes only separate once all three parts sit next to each other. A JWT is three base64url segments: a header, a payload and a signature. The signature covers the first two, joined by a dot. That structure explains almost every attack, because it means a reader must decide whether to trust the header's contents before it can check anything. That decision is the alg field, and the serious problems live there. A token declaring alg none carries no signature to verify. Worse, a server accepting whatever algorithm the header names can be handed a token where alg says HMAC and the public RSA key is used as the shared secret, producing a signature the attacker can produce themselves. The defence is to ignore the header and configure the expected algorithm, which is what RFC 8725 asks for and what a surprising number of libraries do not do by default. Claims need the same scrutiny. exp and nbf are checked against the clock on the verifying side, so a few minutes of drift is normal and a lot of it is a bug. iss and aud decide which system a token was meant for, and a token skipping either check can be replayed against the wrong service. jti exists for revocation and does nothing unless somebody keeps a list. I cover where the token lives too. localStorage survives a reload and is readable by any script that runs, which turns one injection bug into session theft. Cookies with HttpOnly and the right SameSite setting narrow that, and the trade-off deserves stating plainly.

    Share

    Frequently Asked Questions

    PreviousHow Do QR Codes Work? From Text to Scannable PatternNextBest AI Writing Assistants 2026: Free & Compared

    Comments

    Leave a Review

    Rate this tool
    Overall Rating
    Spam Protection Active