<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Openid-Connect on Sauvik Biswas</title>
    <link>https://sauvikbiswas.com/tags/openid-connect/</link>
    <description>Recent content in Openid-Connect on Sauvik Biswas</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Mon, 22 Jun 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://sauvikbiswas.com/tags/openid-connect/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>JWKS and RS256: Dropping the Shared JWT Secret</title>
      <link>https://sauvikbiswas.com/posts/learning-oauth-2-08/</link>
      <pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://sauvikbiswas.com/posts/learning-oauth-2-08/</guid>
      <description>&lt;h2 class=&#34;heading&#34; id=&#34;why-verify-only-apps-shouldnt-hold-the-signing-key&#34;&gt;&#xA;  Why verify-only apps shouldn&amp;rsquo;t hold the signing key&#xA;  &lt;a class=&#34;anchor&#34; href=&#34;#why-verify-only-apps-shouldnt-hold-the-signing-key&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://sauvikbiswas.com/posts/learning-oauth-2-07/&#34;&gt;v07&lt;/a&gt; added OpenID Connect on top of v06&amp;rsquo;s split architecture. The &lt;code&gt;id_token&lt;/code&gt; is a signed JWT. Mode B access tokens are JWTs too. Both used HS256 with a shared &lt;code&gt;JWT_SECRET&lt;/code&gt; copied into three &lt;code&gt;.env&lt;/code&gt; files.&lt;/p&gt;&#xA;&lt;p&gt;That worked in a toy lab. It is not how production IdPs ship.&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Concern&lt;/th&gt;&#xA;          &lt;th&gt;v07 (HS256 + &lt;code&gt;JWT_SECRET&lt;/code&gt;)&lt;/th&gt;&#xA;          &lt;th&gt;v08 (RS256 + JWKS)&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Who can &lt;em&gt;sign&lt;/em&gt; tokens?&lt;/td&gt;&#xA;          &lt;td&gt;Any process with &lt;code&gt;JWT_SECRET&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Only the auth server (private key)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Who can &lt;em&gt;verify&lt;/em&gt; tokens?&lt;/td&gt;&#xA;          &lt;td&gt;Any process with &lt;code&gt;JWT_SECRET&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Anyone with the public key from &lt;code&gt;jwks_uri&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Key rotation&lt;/td&gt;&#xA;          &lt;td&gt;Re-sync &lt;code&gt;JWT_SECRET&lt;/code&gt; everywhere&lt;/td&gt;&#xA;          &lt;td&gt;Publish new key in JWKS; verifiers pick by &lt;code&gt;kid&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Discovery&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;id_token_signing_alg_values_supported: [&amp;quot;HS256&amp;quot;]&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;[&amp;quot;RS256&amp;quot;]&lt;/code&gt; + &lt;code&gt;jwks_uri&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Real IdPs (Google, Okta, Auth0)&lt;/td&gt;&#xA;          &lt;td&gt;Not available (no shared secret)&lt;/td&gt;&#xA;          &lt;td&gt;RS256; public keys at &lt;code&gt;jwks_uri&lt;/code&gt; in discovery&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h3 class=&#34;heading&#34; id=&#34;what-hs256-actually-means&#34;&gt;&#xA;  What HS256 actually means&#xA;  &lt;a class=&#34;anchor&#34; href=&#34;#what-hs256-actually-means&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h3&gt;&#xA;&lt;p&gt;HS256 is symmetric: one secret signs and verifies. In v07, the client verified &lt;code&gt;id_token&lt;/code&gt; with &lt;code&gt;JWT_SECRET&lt;/code&gt; and the resource server verified Mode B access tokens with the same secret while the auth server signed with it.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Intermission: What Industry Ships and Who Gets Paid</title>
      <link>https://sauvikbiswas.com/posts/learning-oauth-2-intermission-01/</link>
      <pubDate>Sun, 21 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://sauvikbiswas.com/posts/learning-oauth-2-intermission-01/</guid>
      <description>&lt;h2 class=&#34;heading&#34; id=&#34;a-deliberate-pause&#34;&gt;&#xA;  A deliberate pause&#xA;  &lt;a class=&#34;anchor&#34; href=&#34;#a-deliberate-pause&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://sauvikbiswas.com/posts/learning-oauth-2-07/&#34;&gt;v07&lt;/a&gt; is in the repo. It consists of OpenID Connect on top of the &lt;a href=&#34;https://sauvikbiswas.com/posts/learning-oauth-2-06/&#34;&gt;v06&lt;/a&gt; split; i.e. &lt;code&gt;id_token&lt;/code&gt;, discovery, UserInfo, &lt;code&gt;nonce&lt;/code&gt;, and the &lt;code&gt;openid&lt;/code&gt; scope; while keeping v06&amp;rsquo;s opaque-or-JWT access-token modes. The runnable snapshot is &lt;a href=&#34;https://github.com/sauvikbiswas/oauth-lab/tree/main/versions/v07-openid-connect&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;versions/v07-openid-connect/&lt;/code&gt;&lt;/a&gt;. In my opinion, that is a lot of ground for seven incremental snapshots.&lt;/p&gt;&#xA;&lt;p&gt;I started drafting this market-research post earlier, then paused the write-up to implement OIDC first. Almost every commercial IdP ships OAuth and OIDC together; reading vendor pricing without knowing what an &lt;code&gt;id_token&lt;/code&gt; would not be correct. With v07 done, the OAuth+OIDC spine is complete enough to read the landscape.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Adding OpenID Connect on Top of OAuth 2</title>
      <link>https://sauvikbiswas.com/posts/learning-oauth-2-07/</link>
      <pubDate>Sat, 20 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://sauvikbiswas.com/posts/learning-oauth-2-07/</guid>
      <description>&lt;h2 class=&#34;heading&#34; id=&#34;why-v06-is-not-enough&#34;&gt;&#xA;  Why v06 is not enough&#xA;  &lt;a class=&#34;anchor&#34; href=&#34;#why-v06-is-not-enough&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://sauvikbiswas.com/posts/learning-oauth-2-06/&#34;&gt;v06&lt;/a&gt; split the authorization server from the resource server and taught token validation across process boundaries. That is production-shaped OAuth 2.0.&lt;/p&gt;&#xA;&lt;p&gt;It is not OpenID Connect. Vendors market themselves as OpenID Providers because OIDC standardizes &lt;em&gt;authentication&lt;/em&gt; (who logged in) on top of OAuth&amp;rsquo;s &lt;em&gt;authorization&lt;/em&gt; (what APIs this token may call). While technically it&amp;rsquo;s not part of OAuth 2 specs; and I had steered clear of implementing it; I decided to tackle this as well since I was working on a piece that covered what&amp;rsquo;s available out there and what their business was. In almost all cases IdP (Identity providers) implement OIDC on top of OAuth.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
