<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Muiz Haruna</title>
    <description>The latest articles on DEV Community by Muiz Haruna (@devdesiignn).</description>
    <link>https://dev.to/devdesiignn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4019381%2F08c112e1-d945-4941-ad42-2c7c4309606d.png</url>
      <title>DEV Community: Muiz Haruna</title>
      <link>https://dev.to/devdesiignn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devdesiignn"/>
    <language>en</language>
    <item>
      <title>Web Security: Understanding JWT</title>
      <dc:creator>Muiz Haruna</dc:creator>
      <pubDate>Wed, 05 Aug 2026 14:43:58 +0000</pubDate>
      <link>https://dev.to/devdesiignn/web-security-understanding-jwt-2749</link>
      <guid>https://dev.to/devdesiignn/web-security-understanding-jwt-2749</guid>
      <description>&lt;h2&gt;
  
  
  JWT: JSON Web Token
&lt;/h2&gt;

&lt;p&gt;JWT is a standard for safely passing claims, &lt;strong&gt;&lt;em&gt;pieces of information or assertions made about a subject&lt;/em&gt;&lt;/strong&gt;, in a space-constrained environment.&lt;/p&gt;

&lt;p&gt;Its key features are compactness, simplicity, and usability.&lt;/p&gt;

&lt;p&gt;A JWT often looks like gibberish, but it is a very compact representation of claims, together with a signature to verify its authenticity.&lt;/p&gt;

&lt;p&gt;Here's an encoded JWT:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's what it decodes to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Header:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"alg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HS256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typ"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JWT"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Payload:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1234567890"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1516239022&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claims are also known as assertions made about a certain party or object.&lt;/p&gt;

&lt;p&gt;Some claims and their meaning are defined as part of the JWT specification, known as &lt;strong&gt;Registered claims&lt;/strong&gt;, while others are user-defined.&lt;/p&gt;

&lt;p&gt;Registered claims, e.g., &lt;code&gt;iss&lt;/code&gt; (issuer), &lt;code&gt;sub&lt;/code&gt; (subject), &lt;code&gt;aud&lt;/code&gt; (audience), &lt;code&gt;exp&lt;/code&gt; (expiration time), &lt;code&gt;iat&lt;/code&gt; (issued at), and &lt;code&gt;jti&lt;/code&gt; (JWT ID) have standardized meanings under RFC 7519, so any system that reads a JWT knows what to expect from them.&lt;/p&gt;

&lt;p&gt;Everything else is up to the issuer, e.g., &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, are user-defined, and their meaning is entirely dependent on what the application decides to put there.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why JWT? What does it solve?
&lt;/h2&gt;

&lt;p&gt;JWTs are primarily designed to securely transfer claims between two parties in a simple, optionally validated, and/or encrypted container format.&lt;/p&gt;

&lt;p&gt;There are other ways of asserting claims, such as &lt;a href="https://www.cloudflare.com/learning/access-management/what-is-saml/" rel="noopener noreferrer"&gt;SAML&lt;/a&gt;, which is based on XML, &lt;a href="https://paseto.io/" rel="noopener noreferrer"&gt;PASETO (Platform-Agnostic SEcurity TOkens)&lt;/a&gt;, &lt;a href="https://github.com/return/branca" rel="noopener noreferrer"&gt;Branca&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;PASETO and Branca were created as a response to JWT design flaws; however, JWT still has the highest adoption rate, similar to the REST/GraphQL adoption battle.&lt;/p&gt;

&lt;p&gt;Another great use case for JWT is &lt;strong&gt;client-side (stateless) sessions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Stateless means a server does not keep session records in a database (the traditional method).&lt;/p&gt;

&lt;p&gt;Once a session starts, the server bundles the session data, such as &lt;code&gt;userId&lt;/code&gt;, &lt;code&gt;roles&lt;/code&gt;, and whatever information would previously be stored in the session database row, into a JWT, signs it, and that token is used for session continuity on the client side.&lt;/p&gt;

&lt;p&gt;The server has lost its source of truth, simply because the session token now lives on the client side, and it cannot blindly trust what the client sends back. This is why we have &lt;strong&gt;JSON Web Signature (JWS)&lt;/strong&gt;, which allows the server to verify that the data in the JWT has not been altered.&lt;/p&gt;

&lt;p&gt;While tampering is one concern, privacy is another; some payloads often contain sensitive data.&lt;/p&gt;

&lt;p&gt;If a payload contains sensitive data, &lt;strong&gt;JSON Web Encryption (JWE)&lt;/strong&gt; solves this by encrypting the data, which deters the client and/or anyone intercepting the token from reading its content.&lt;/p&gt;

&lt;p&gt;Most session records only need signing; encryption is only done when certain claims should not be visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Practical Applications
&lt;/h2&gt;

&lt;p&gt;JWT shows up in a handful of recurring patterns across the industry. Here are the most common ones.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authentication &amp;amp; Authorization&lt;/strong&gt;: the most familiar use case. A signed JWT (an access token) is sent with each request, typically as &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt;. This allows the server to verify identity and permissions without a database lookup on every call.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Access &amp;amp; Refresh Tokens&lt;/strong&gt;: in OAuth 2.0-based systems, JWTs are commonly used as &lt;strong&gt;access tokens&lt;/strong&gt;: short-lived, often carrying an expiration and scope, used to prove the client is allowed to access a given resource.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When an access token expires, a longer-lived &lt;strong&gt;refresh token&lt;/strong&gt; is used to request a new one without ending the session and forcing the user to log in again.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Federated Identity, SSO &amp;amp; OpenID Connect&lt;/strong&gt;: JWT is the token format of choice in OAuth 2.0/OIDC-based federated identity systems, where one IdP authenticates a user on behalf of multiple, unrelated services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OIDC in particular defines the &lt;strong&gt;ID token&lt;/strong&gt;: a JWT containing the authenticated user's profile information. I covered the full OAuth 2.0 and OIDC flow, including PKCE, in a &lt;a href="https://dev.to/devdesiignn/web-security-oauth-20-and-openid-connect-oidc-3hff"&gt;previous article&lt;/a&gt;, worth a read if you want the deep dive.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Microservices communication&lt;/strong&gt;: In a distributed system, JWTs let one service pass verified identity and claims to another without a shared session store, which keeps services decoupled and independently scalable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource-constrained environments (IoT)&lt;/strong&gt;: CWT applies the same signed-claims model as JWT but with a binary, more compact encoding, better suited to low-power devices with limited bandwidth.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡Pro Tip
&lt;/h2&gt;

&lt;p&gt;JWT is an open standard for representing information, called claims, as a concise JSON object. &lt;a href="https://cbor.io/" rel="noopener noreferrer"&gt;CWT&lt;/a&gt; (CBOR Web Token) serves the same purpose but uses Concise Binary Object Representation (CBOR) instead of JSON, making it better suited for low-power, resource-constrained IoT transmissions.&lt;/p&gt;

&lt;p&gt;Thanks for reading, catch you in the next one.&lt;/p&gt;

</description>
      <category>jwt</category>
      <category>security</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>Web Security: OAuth 2.0 and OpenID Connect (OIDC)</title>
      <dc:creator>Muiz Haruna</dc:creator>
      <pubDate>Tue, 07 Jul 2026 15:18:49 +0000</pubDate>
      <link>https://dev.to/devdesiignn/web-security-oauth-20-and-openid-connect-oidc-3hff</link>
      <guid>https://dev.to/devdesiignn/web-security-oauth-20-and-openid-connect-oidc-3hff</guid>
      <description>&lt;h2&gt;
  
  
  OAuth 2.0: Open Authorization
&lt;/h2&gt;

&lt;p&gt;In the past, sharing information between services was often done by sharing login credentials with the other service, trusting that service to protect the credentials and not exceed the intended scope of the shared information.&lt;/p&gt;

&lt;p&gt;Now enter &lt;strong&gt;standards&lt;/strong&gt;. Standards are documented, agreed-upon rules, guidelines, and best practices that dictate how software is written, tested, and maintained.&lt;/p&gt;

&lt;p&gt;OAuth is a security standard that allows you to securely give one app permission to access your data in another application. It is similar to giving a person a keycard with specific permissions and bounds.&lt;/p&gt;

&lt;p&gt;This is known as &lt;strong&gt;authorization&lt;/strong&gt;, or &lt;strong&gt;delegated authorization&lt;/strong&gt;, or simply &lt;strong&gt;delegation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The keycard is not set in stone; you can revoke or take back the permission at any time you wish.&lt;/p&gt;

&lt;p&gt;A real-life scenario: you have a matrix LED board that you want to show your GitHub activity graph on. The matrix board needs to access your GitHub data in order to display your activity graph. The connection between your matrix board and GitHub will be handled by OAuth 2.0.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why OAuth 2.0? What Happened to 1.0?
&lt;/h2&gt;

&lt;p&gt;OAuth 1.0, although really secure because it uses cryptographic signatures for every request, was not very developer-friendly. OAuth 2.0 simplified the experience significantly while keeping the security intact when implemented correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  The OAuth Flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Terminologies
&lt;/h3&gt;

&lt;p&gt;Before walking through the flow, here are the key players and concepts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Four Actors:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resource Owner (you)&lt;/strong&gt; — the person who owns the data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client&lt;/strong&gt; — the application that needs your data or wants to perform certain actions on your behalf&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization Server&lt;/strong&gt; — the application that knows you, or the application you can prove to that you really are you&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Server&lt;/strong&gt; — the application or service the client wants to use to perform actions on your behalf&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: the Authorization Server and Resource Server could be part of the same thing, or could be separated entirely. In a case where they are separate, the Authorization Server has to trust the Resource Server, and vice versa.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Core Concepts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redirect URI&lt;/strong&gt; — the URL the Authorization Server will redirect the Resource Owner back to after permission is granted. It is set by the client and is also known as the callback URL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response Type&lt;/strong&gt; — the type of information the client wants to see. The most common type is &lt;code&gt;code&lt;/code&gt;, where the client expects to receive an authorization code. Other types include &lt;code&gt;token&lt;/code&gt;, &lt;code&gt;id_token&lt;/code&gt;, multiple responses, and &lt;code&gt;none&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope&lt;/strong&gt; — the granular permission the client wants, with respect to the data or the action they want to perform&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consent&lt;/strong&gt; — the Authorization Server builds out a consent form based on the scopes the client is requesting, and serves that form to the Resource Owner to decide whether to grant access or not&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client ID&lt;/strong&gt; — used to identify the client at the Authorization Server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client Secret&lt;/strong&gt; — a secret password only the client and the Authorization Server know. It allows both to securely share information privately, behind the scenes. It must never be exposed on the frontend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization Code&lt;/strong&gt; — a temporary, short-lived code the Authorization Server sends back to the client. The client then privately sends the authorization code back to the Authorization Server along with some other information, like the client secret, in exchange for an access token. This process is called the &lt;strong&gt;token exchange&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Token&lt;/strong&gt; — the token the client will use to communicate with the Resource Server. It is short-lived by design — the less time it is valid, the less damage it can do if it gets stolen&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refresh Token&lt;/strong&gt; — a long-lived token used to get a new access token when the current one expires, without making the user log in again. It never goes to the Resource Server — it only ever goes back to the Authorization Server. Because it travels less, it is much harder to steal. In most systems, the refresh token is stored in an &lt;code&gt;HttpOnly&lt;/code&gt; cookie on the backend, so JavaScript cannot touch it at all&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  The Auth Code Flow
&lt;/h3&gt;

&lt;p&gt;Using the matrix board and GitHub as the example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You (Resource Owner) want your matrix LED board (Client) to access your GitHub data to display your GitHub graph&lt;/li&gt;
&lt;li&gt;Your matrix board sends a permission request to the GitHub Authorization Server — it adds the &lt;code&gt;client_id&lt;/code&gt;, &lt;code&gt;redirect_uri&lt;/code&gt;, &lt;code&gt;response_type&lt;/code&gt;, and &lt;code&gt;scope&lt;/code&gt; to the request&lt;/li&gt;
&lt;li&gt;The Authorization Server prompts you with a consent form based on the scopes it got from the client&lt;/li&gt;
&lt;li&gt;You grant permission — the Authorization Server redirects back to the client using the &lt;code&gt;redirect_uri&lt;/code&gt; + a temporary authorization code&lt;/li&gt;
&lt;li&gt;The client securely sends its &lt;code&gt;client_id&lt;/code&gt;, &lt;code&gt;client_secret&lt;/code&gt;, and the authorization code it just got, back to the Authorization Server&lt;/li&gt;
&lt;li&gt;The Authorization Server verifies these and responds with an access token&lt;/li&gt;
&lt;li&gt;The access token is used to request resources from the GitHub REST API (Resource Server)&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prerequisite:&lt;/strong&gt; Before any OAuth exchange, the client must have gotten a &lt;code&gt;client_id&lt;/code&gt; and maybe a &lt;code&gt;client_secret&lt;/code&gt; from the Authorization Server. This process is called &lt;strong&gt;app registration&lt;/strong&gt; — that is the only way the Authorization Server can identify a client. The &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; are sometimes called &lt;code&gt;app_id&lt;/code&gt; or &lt;code&gt;app_secret&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — What the permission request actually looks like:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://github.com/login/oauth/authorize
  ?client_id=abc123
  &amp;amp;redirect_uri=http://localhost:5173/callback
  &amp;amp;response_type=code
  &amp;amp;scope=read:user%20user:email
  &amp;amp;state=random_string_for_csrf_protection
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4 — What the redirect back to the client looks like:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET http://localhost:5173/callback
  ?code=temporary_auth_code_here
  &amp;amp;state=random_string_for_csrf_protection
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5 — What the token exchange request looks like (server to server):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://github.com/login/oauth/access_token&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"client_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"client_secret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"supersecretvalue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"temporary_auth_code_here"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"redirect_uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:5173/callback"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 6 — What the Authorization Server responds with:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"access_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gho_16C7e42F292c6912E7710c838347Ae178B4a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"token_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bearer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"read:user,user:email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"refresh_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ghr_1B4a2e77838347a7E420ce178F2E7c6912E169"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expires_in"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28800&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 7 — Using the access token to request data from the Resource Server:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://api.github.com/user
Authorization: Bearer gho_16C7e42F292c6912E7710c838347Ae178B4a
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  PKCE — Proof Key for Code Exchange
&lt;/h2&gt;

&lt;p&gt;The flow described above is usually for &lt;strong&gt;confidential clients&lt;/strong&gt; — server or backend apps that can securely store the client secret.&lt;/p&gt;

&lt;p&gt;PKCE is a security extension for the OAuth 2.0 protocol, built to ensure that the app asking for permission is indeed the one receiving the access token. It is used to keep &lt;strong&gt;public clients&lt;/strong&gt; safe from code theft.&lt;/p&gt;

&lt;p&gt;Public clients are applications that run in environments where credentials cannot be kept confidential, because the application code executes directly on the user's device or in the browser, and any embedded credentials can be decompiled, extracted, or inspected.&lt;/p&gt;

&lt;p&gt;PKCE creates a &lt;strong&gt;dynamic, one-time-use secret for every single login flow&lt;/strong&gt;. Since the secret changes every time, it is practically useless to a hacker even if intercepted.&lt;/p&gt;

&lt;h3&gt;
  
  
  The PKCE Flow
&lt;/h3&gt;

&lt;p&gt;Very similar to the auth code flow, but with a little twist:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The app creates two values — a &lt;code&gt;code_verifier&lt;/code&gt; and a &lt;code&gt;code_challenge&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The app sends the permission request + its &lt;code&gt;client_id&lt;/code&gt;, &lt;code&gt;scope&lt;/code&gt;, &lt;code&gt;redirect_uri&lt;/code&gt;, &lt;code&gt;code_challenge&lt;/code&gt;, and &lt;code&gt;code_challenge_method&lt;/code&gt; to the Authorization Server&lt;/li&gt;
&lt;li&gt;The Resource Owner grants permission — the Authorization Server sends the authorization code to the client as usual&lt;/li&gt;
&lt;li&gt;The app sends its &lt;code&gt;client_id&lt;/code&gt;, &lt;code&gt;code_verifier&lt;/code&gt;, and authorization code back to the Authorization Server in exchange for an access token&lt;/li&gt;
&lt;li&gt;The Authorization Server hashes the &lt;code&gt;code_verifier&lt;/code&gt; and checks it matches the &lt;code&gt;code_challenge&lt;/code&gt; it received earlier — if it matches, it issues the access token&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — What the PKCE permission request looks like:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://github.com/login/oauth/authorize
  ?client_id=abc123
  &amp;amp;redirect_uri=http://localhost:5173/callback
  &amp;amp;response_type=code
  &amp;amp;scope=read:user%20user:email
  &amp;amp;code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &amp;amp;code_challenge_method=S256
  &amp;amp;state=random_string_for_csrf_protection
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4 — What the token exchange looks like with PKCE (no client secret needed):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://github.com/login/oauth/access_token&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"client_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"temporary_auth_code_here"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"redirect_uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:5173/callback"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code_verifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In recent times, confidential apps are also now required to use PKCE as an additional layer of security.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  OpenID Connect (OIDC)
&lt;/h2&gt;

&lt;p&gt;OAuth 2.0 is designed only for authorization — for granting access to data and features from one app to another. OAuth is like giving the client a keycard, but it does not say anything about the keycard holder.&lt;/p&gt;

&lt;p&gt;OIDC is a thin layer built on top of OAuth to add information about the logged-in user. It is like giving the client a badge that contains the permissions and some basic information about the Resource Owner.&lt;/p&gt;

&lt;p&gt;OAuth is simply authorization (access) from one app to another, while OIDC is a client establishing a session (authentication).&lt;/p&gt;

&lt;p&gt;When an Authorization Server supports OIDC, it is often called an &lt;strong&gt;Identity Provider (IdP)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;OIDC also enables &lt;strong&gt;Single Sign-On (SSO)&lt;/strong&gt; — where one login accesses multiple clients, all federated by one single identity.&lt;/p&gt;

&lt;p&gt;OAuth is like an ATM + the internal banking infrastructure, while OIDC is like the ATM card — it carries basic information about the card owner.&lt;/p&gt;

&lt;h3&gt;
  
  
  The OIDC Flow
&lt;/h3&gt;

&lt;p&gt;The flow is similar to the OAuth flow, but with a minimum requirement of adding &lt;code&gt;openid&lt;/code&gt; to the scope in the permission request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scope=openid%20profile%20email
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In return, an &lt;code&gt;id_token&lt;/code&gt; is returned together with the access token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the Authorization Server response looks like with OIDC:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"access_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gho_16C7e42F292c6912E7710c838347Ae178B4a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"token_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bearer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expires_in"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"refresh_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ghr_1B4a2e77838347a7E420ce178F2E7c6912E169"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTYiLCJuYW1lIjoiTXVpeiBBZGV3YWxlIiwiZW1haWwiOiJtdWl6QGV4YW1wbGUuY29tIiwicGljdHVyZSI6Imh0dHBzOi8vYXZhdGFycy5naXRodWJ1c2VyY29udGVudC5jb20vdS8xMjM0NTYiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaWF0IjoxNzE2MDAwMDAwLCJleHAiOjE3MTYwMDM2MDB9.signature"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ID Token&lt;/strong&gt; — a JWT (JSON Web Token). The data inside it are called &lt;strong&gt;claims&lt;/strong&gt;. When you decode that &lt;code&gt;id_token&lt;/code&gt; above, here is what you actually get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Muiz Adewale"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"muiz@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"picture"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://avatars.githubusercontent.com/u/123456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1716000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1716003600&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OIDC handles &lt;strong&gt;who you are&lt;/strong&gt;. OAuth handles &lt;strong&gt;what you are allowed to do&lt;/strong&gt;. Most Authorization Servers also handle authentication.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the Frontend Actually Uses the ID Token
&lt;/h2&gt;

&lt;p&gt;This is where it gets interesting for frontend developers, because there are two real-world patterns for reading user identity on the client side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pattern 1 — Decode the ID Token directly on the frontend&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ID Token is a JWT, which means it is just a Base64-encoded string. The frontend can decode it client-side and read the claims directly — the user's name, email, profile picture, and so on — without making an additional network request.&lt;/p&gt;

&lt;p&gt;But here is an important distinction: &lt;strong&gt;decoding is not the same as verifying.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Anyone can decode a JWT. To actually trust its contents, you need to verify its signature — confirming it was genuinely issued by the Authorization Server and has not been tampered with.&lt;/p&gt;

&lt;p&gt;This is where the &lt;strong&gt;OpenID Configuration endpoint&lt;/strong&gt; comes in, commonly found at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://{the-auth-server}/.well-known/openid-configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a publicly available JSON document that describes the Authorization Server. Here is what it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"issuer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://accounts.google.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"authorization_endpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://accounts.google.com/o/oauth2/v2/auth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"token_endpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://oauth2.googleapis.com/token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"userinfo_endpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://openidconnect.googleapis.com/v1/userinfo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jwks_uri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.googleapis.com/oauth2/v3/certs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scopes_supported"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"openid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"response_types_supported"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id_token"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"grant_types_supported"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"authorization_code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"refresh_token"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;jwks_uri&lt;/code&gt; is where the Authorization Server's public keys live. Those public keys are what you use to verify the ID Token's signature before trusting any of the claims inside it.&lt;/p&gt;

&lt;p&gt;In practice, most frontends do not do the verification themselves — that is the backend's job. The frontend decodes the token to read claims for display purposes only, trusting that the backend has already validated it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pattern 2 — Hit the &lt;code&gt;/userinfo&lt;/code&gt; or &lt;code&gt;/profile&lt;/code&gt; endpoint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of decoding the ID Token on the frontend, the client can send the Access Token to the Authorization Server's &lt;code&gt;/userinfo&lt;/code&gt; endpoint — or a custom &lt;code&gt;/profile&lt;/code&gt; endpoint configured on the backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /userinfo
Authorization: Bearer gho_16C7e42F292c6912E7710c838347Ae178B4a
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server validates the token and returns the user's profile as a plain JSON object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Muiz Adewale"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"muiz@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"picture"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://avatars.githubusercontent.com/u/123456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both &lt;code&gt;/userinfo&lt;/code&gt; and &lt;code&gt;/profile&lt;/code&gt; are backend-configured. &lt;code&gt;/userinfo&lt;/code&gt; is the OIDC spec standard — every OIDC-compliant Identity Provider is required to expose it. &lt;code&gt;/profile&lt;/code&gt; is a custom backend endpoint that many systems expose to do the same job in their own way.&lt;/p&gt;

&lt;p&gt;This pattern is simpler for the frontend — no JWT decoding needed, just a regular JSON response you can use directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which pattern is more common?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both are widely used. Pattern 1 is faster since there is no extra network call. Pattern 2 is simpler for the frontend and keeps JWT handling off the client entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Putting It Together
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;OAuth 2.0&lt;/th&gt;
&lt;th&gt;OIDC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Authorization (access)&lt;/td&gt;
&lt;td&gt;Authentication (identity)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Answers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;What can this app do?&lt;/td&gt;
&lt;td&gt;Who is this user?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Token&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Access Token&lt;/td&gt;
&lt;td&gt;ID Token (JWT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Delegated resource access&lt;/td&gt;
&lt;td&gt;Login, SSO, user profile&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  A Personal Note
&lt;/h2&gt;

&lt;p&gt;Auth is something most frontend developers treat as a black box — something that happens on the backend, something you just hook into and move on. OAuth and OIDC feel like backend territory. I used to think the same.&lt;/p&gt;

&lt;p&gt;But OAuth and OIDC are part of web security, and web security is not just a backend thing. It lives in every redirect, every token stored in memory, every scope decision your frontend participates in — whether you are aware of it or not.&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>sso</category>
      <category>websecurity</category>
      <category>openidconnect</category>
    </item>
  </channel>
</rss>
