<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>keycloak docker on Digi Hunch</title><link>https://www.digihunch.com/tag/keycloak-docker/</link><description>Recent content in keycloak docker on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Wed, 02 Apr 2025 10:41:25 -0400</lastBuildDate><atom:link href="https://www.digihunch.com/tag/keycloak-docker/index.xml" rel="self" type="application/rss+xml"/><item><title>Test Open ID Connect Flows Locally</title><link>https://www.digihunch.com/2024/08/test-open-id-connect-flows-locally/</link><pubDate>Mon, 05 Aug 2024 13:24:34 -0400</pubDate><guid>https://www.digihunch.com/2024/08/test-open-id-connect-flows-locally/</guid><description>&lt;img src="https://www.digihunch.com/wp-content/uploads/2025/04/feature-local-oidc-test.webp" alt="Featured image of post Test Open ID Connect Flows Locally" /&gt;&lt;p class="wp-block-paragraph"&gt;Earlier this year, I had to integrate an application with an identity provider. Both claim to be compliant with &lt;a href="https://www.digihunch.com/2023/07/oauth-2-0-and-oidc-2-of-2/"&gt;Open ID Connect&lt;/a&gt;. But when they don&amp;#8217;t get along, I must find out where it breaks to determine which party isn&amp;#8217;t compliant. Therefore, I had to really get to the transaction-level details. As a result, I was eager to find out a way to test Open ID Connect Flows locally. Considering that I discussed OIDC in several past &lt;a href="https://www.digihunch.com/2023/07/oauth-2-0-and-oidc-2-of-2/"&gt;articles&lt;/a&gt; and use cases (&lt;a href="https://www.digihunch.com/2023/07/authenticate-kube-apiserver-via-oidc/"&gt;authenticating to kube-api server&lt;/a&gt;, Kubernetes &lt;a href="https://www.digihunch.com/2023/12/workload-identity-on-kubernetes-1-of-2-aks/"&gt;workload&lt;/a&gt;, &lt;a href="https://www.digihunch.com/2023/06/kubernetes-paas-and-red-hat-openshift/"&gt;ROSA&lt;/a&gt;), I feel it is important to be able to test Open ID Connect flows locally.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Architecture&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;What makes local testing difficult is that there are several parties involved and they act in different roles. Take &lt;a href="https://www.digihunch.com/2023/07/oauth-2-0-and-oidc-2-of-2/"&gt;Authorization Code Flow&lt;/a&gt; as an example, the main actors are:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;User Agent: the browser;&lt;/li&gt;&#10;&lt;li&gt;Authorization Server: an identity store, also referred to as identity provider;&lt;/li&gt;&#10;&lt;li&gt;Resource server: an HTTP server that returns protected resource;&lt;/li&gt;&#10;&lt;li&gt;OIDC client application: the component that communicates with identity store on behalf of the resource server;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Apart from the bowser (obviously running on my laptop), we can group the the other actors in different patterns. Here I illustrate some options below:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="751px" viewBox="-0.5 -0.5 751 731" style="max-width:100%;max-height:731px;"&gt;&lt;defs&gt;&lt;/defs&gt;&lt;g&gt;&lt;g data-cell-id="0"&gt;&lt;g data-cell-id="1"&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-68"&gt;&lt;g&gt;&lt;rect x="0" y="0" width="750" height="730" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-62"&gt;&lt;g&gt;&lt;rect x="370" y="580" width="370" height="110" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-end; width: 368px; height: 1px; padding-top: 587px; margin-left: 370px;"&gt;&lt;div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: right;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Server Pattern&lt;div&gt;Example #4&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="738" y="599" fill="#333333" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="end"&gt;Server Pattern&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-61"&gt;&lt;g&gt;&lt;rect x="370" y="232.5" width="260" height="80" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-end; width: 258px; height: 1px; padding-top: 239px; margin-left: 370px;"&gt;&lt;div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: right;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Server Pattern&lt;div&gt;Example #2&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="628" y="251" fill="#333333" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="end"&gt;Server Pattern&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-58"&gt;&lt;g&gt;&lt;rect x="370" y="80" width="260" height="80" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-end; width: 258px; height: 1px; padding-top: 87px; margin-left: 370px;"&gt;&lt;div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: right;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Server Pattern&lt;div&gt;Example #1&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="628" y="99" fill="#333333" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="end"&gt;Server Pattern&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-48"&gt;&lt;g&gt;&lt;rect x="10" y="490" width="220" height="225" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 218px; height: 1px; padding-top: 497px; margin-left: 12px;"&gt;&lt;div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Client&amp;nbsp;&lt;span style="background-color: initial;"&gt;Pattern Ex.#3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="12" y="509" fill="#333333" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px"&gt;Client&amp;nbsp;Pattern Ex.#3&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-47"&gt;&lt;g&gt;&lt;rect x="10" y="250" width="220" height="220" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 218px; height: 1px; padding-top: 257px; margin-left: 12px;"&gt;&lt;div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Client Pattern&lt;div&gt;Example #2&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="12" y="269" fill="#333333" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px"&gt;Client Pattern&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-46"&gt;&lt;g&gt;&lt;rect x="10" y="60" width="220" height="180" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 218px; height: 1px; padding-top: 67px; margin-left: 12px;"&gt;&lt;div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Client Pattern&lt;div&gt;Example #1&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="12" y="79" fill="#333333" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px"&gt;Client Pattern&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-23"&gt;&lt;g&gt;&lt;rect x="25" y="520" width="200" height="90" rx="13.5" ry="13.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 198px; height: 1px; padding-top: 527px; margin-left: 26px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Advanced Reverse Proxy&lt;div&gt;(e.g. Nginx Plus, Traefik Enterprise)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="125" y="539" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Advanced Reverse Proxy&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-3"&gt;&lt;g&gt;&lt;rect x="40" y="150" width="180" height="80" rx="12" ry="12" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 157px; margin-left: 41px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;&lt;div&gt;&lt;span style="background-color: initial;"&gt;App (with built-in&amp;nbsp;&lt;/span&gt;&lt;span style="background-color: initial;"&gt;OIDC support)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="130" y="169" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;App (with built-in&amp;nbsp;OIDC suppor&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-4"&gt;&lt;g&gt;&lt;rect x="600" y="620" width="130" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 650px; margin-left: 601px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Identity Provider with&lt;div&gt;OIDC support&amp;nbsp;&lt;/div&gt;&lt;div&gt;(e.g. Active Directory)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="665" y="654" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Identity Provider wit&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-5"&gt;&lt;g&gt;&lt;path d="M 240 720 L 240 20" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-6"&gt;&lt;g&gt;&lt;rect x="35" y="10" width="160" height="30" fill="none" stroke="none" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 25px; margin-left: 36px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"&gt;OIDC Client App Patterns&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="115" y="29" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle" font-weight="bold"&gt;OIDC Client App Patterns&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-7"&gt;&lt;g&gt;&lt;rect x="390" y="10" width="220" height="30" fill="none" stroke="none" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 25px; margin-left: 391px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"&gt;OIDC Authorization Server Patterns&lt;div&gt;(including Identity Provider)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="500" y="29" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle" font-weight="bold"&gt;OIDC Authorization Server Patterns&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-8"&gt;&lt;g&gt;&lt;path d="M 360 720 L 360 20" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-9"&gt;&lt;g&gt;&lt;ellipse cx="85" cy="200" rx="35" ry="25" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 200px; margin-left: 51px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;HTTP&lt;div&gt;Resource&lt;/div&gt;&lt;div&gt;&lt;span style="background-color: initial;"&gt;Server&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="85" y="204" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;HTTP&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-15"&gt;&lt;g&gt;&lt;ellipse cx="135" cy="345" rx="50" ry="15" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 345px; margin-left: 86px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;oauth2-proxy&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="135" y="349" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;oauth2-proxy&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-16"&gt;&lt;g&gt;&lt;rect x="380" y="90" width="160" height="60" rx="9" ry="9" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 120px; margin-left: 381px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Self-hosted OIDC-capable&lt;div&gt;Identity Providers&lt;/div&gt;&lt;div&gt;(e.g. KeyCloak as IdP)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="460" y="124" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Self-hosted OIDC-capable&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-17"&gt;&lt;g&gt;&lt;rect x="50" y="380" width="170" height="80" rx="12" ry="12" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 168px; height: 1px; padding-top: 387px; margin-left: 51px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;&lt;div&gt;&lt;span style="background-color: initial;"&gt;App (without&amp;nbsp;&lt;/span&gt;&lt;span style="background-color: initial;"&gt;OIDC capability)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="135" y="399" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;App (without&amp;nbsp;OIDC capability)&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-18"&gt;&lt;g&gt;&lt;ellipse cx="175" cy="200" rx="35" ry="20" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 200px; margin-left: 141px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;OIDC&lt;div&gt;library&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="175" y="204" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;OIDC&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-20"&gt;&lt;g&gt;&lt;ellipse cx="82.5" cy="580" rx="47.5" ry="20" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 93px; height: 1px; padding-top: 580px; margin-left: 36px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;reverse&amp;nbsp;&lt;span style="background-color: initial;"&gt;proxy&lt;/span&gt;&lt;div&gt;capability&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="83" y="584" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;reverse&amp;nbsp;proxy&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-24"&gt;&lt;g&gt;&lt;ellipse cx="175" cy="580" rx="40" ry="20" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 580px; margin-left: 136px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;oidc client&lt;div&gt;capability&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="175" y="584" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;oidc client&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-27"&gt;&lt;g&gt;&lt;rect x="380" y="242.5" width="160" height="60" rx="9" ry="9" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 272px; margin-left: 381px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;&lt;div&gt;Commercial OIDC-capable&lt;/div&gt;Identity Providers&lt;div&gt;(e.g. MS Entra-ID, Google)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="460" y="276" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Commercial OIDC-capableIde&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-35"&gt;&lt;g&gt;&lt;rect x="85" y="90" width="90" height="45" rx="6.75" ry="6.75" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 113px; margin-left: 86px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;(optional)&lt;div&gt;reverse proxy&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="130" y="116" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;(optional)&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-36"&gt;&lt;g&gt;&lt;ellipse cx="135" cy="425" rx="35" ry="25" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 425px; margin-left: 101px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;HTTP&lt;div&gt;Resource&lt;/div&gt;&lt;div&gt;&lt;span style="background-color: initial;"&gt;Server&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="135" y="429" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;HTTP&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-37"&gt;&lt;g&gt;&lt;rect x="90" y="275" width="90" height="37.5" rx="5.63" ry="5.63" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 294px; margin-left: 91px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;(optional)&lt;div&gt;reverse proxy&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="135" y="297" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;(optional)&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-38"&gt;&lt;g&gt;&lt;rect x="25" y="630" width="200" height="80" rx="12" ry="12" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 198px; height: 1px; padding-top: 637px; margin-left: 26px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;&lt;div&gt;&lt;span style="background-color: initial;"&gt;App (without&amp;nbsp;&lt;/span&gt;&lt;span style="background-color: initial;"&gt;OIDC capability)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="125" y="649" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;App (without&amp;nbsp;OIDC capability)&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-39"&gt;&lt;g&gt;&lt;ellipse cx="125" cy="680" rx="35" ry="25" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 680px; margin-left: 91px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;HTTP&lt;div&gt;Resource&lt;/div&gt;&lt;div&gt;&lt;span style="background-color: initial;"&gt;Server&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="125" y="684" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;HTTP&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-40"&gt;&lt;g&gt;&lt;path d="M 135 312.5 L 135 323.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 135 328.88 L 131.5 321.88 L 135 323.63 L 138.5 321.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-41"&gt;&lt;g&gt;&lt;path d="M 135 373.63 L 135 360" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 135 378.88 L 131.5 371.88 L 135 373.63 L 138.5 371.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-42"&gt;&lt;g&gt;&lt;path d="M 130 143.63 L 130 135" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 130 148.88 L 126.5 141.88 L 130 143.63 L 133.5 141.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-50"&gt;&lt;g&gt;&lt;path d="M 125 623.63 L 125 610" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 125 628.88 L 121.5 621.88 L 125 623.63 L 128.5 621.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-52"&gt;&lt;g&gt;&lt;path d="M 130 70 L 130 83.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 130 88.88 L 126.5 81.88 L 130 83.63 L 133.5 81.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-54"&gt;&lt;g&gt;&lt;path d="M 124.73 500 L 124.73 513.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 124.73 518.88 L 121.23 511.88 L 124.73 513.63 L 128.23 511.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-55"&gt;&lt;g&gt;&lt;path d="M 135 255 L 135 268.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 135 273.88 L 131.5 266.88 L 135 268.63 L 138.5 266.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-57"&gt;&lt;g&gt;&lt;rect x="380" y="620" width="120" height="60" rx="9" ry="9" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 650px; margin-left: 381px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;&lt;div&gt;Any OIDC-capable&lt;/div&gt;Identity Broker&amp;nbsp;&lt;div&gt;&lt;span style="background-color: initial;"&gt;e.g. Dex&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="440" y="654" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Any OIDC-capableIden&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-59"&gt;&lt;g&gt;&lt;path d="M 519.45 654.19 L 519.34 664.69 L 500.5 649 L 519.65 633.7 L 519.55 644.2 L 580.55 644.81 L 580.66 634.31 L 599.5 650 L 580.35 665.3 L 580.45 654.8 Z" fill="#fff2cc" stroke="#d6b656" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-60"&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 621px; margin-left: 551px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Other Protocol&lt;div&gt;(e.g. LDAP, SAML)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="551" y="624" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="11px" text-anchor="middle"&gt;Other Protocol&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-34"&gt;&lt;g&gt;&lt;path d="M 275 380 C 255 380 250 400 266 404 C 250 412.8 268 432 281 424 C 290 440 320 440 330 424 C 350 424 350 408 337.5 400 C 350 384 330 368 312.5 376 C 300 364 280 364 275 380 Z" fill="#d5e8d4" stroke="#82b366" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 400px; margin-left: 251px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Standard&lt;div&gt;OIDC Flow&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="300" y="404" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Standard&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-63"&gt;&lt;g&gt;&lt;rect x="370" y="390" width="370" height="110" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-end; width: 368px; height: 1px; padding-top: 397px; margin-left: 370px;"&gt;&lt;div data-drawio-colors="color: #333333; " style="box-sizing: border-box; font-size: 0px; text-align: right;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Server Pattern&lt;div&gt;Example #3&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="738" y="409" fill="#333333" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="end"&gt;Server Pattern&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-64"&gt;&lt;g&gt;&lt;rect x="600" y="430" width="130" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 460px; margin-left: 601px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Identity Provider with&lt;div&gt;OIDC support&amp;nbsp;&lt;/div&gt;&lt;div&gt;(e.g. Active Directory)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="665" y="464" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Identity Provider wit&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-65"&gt;&lt;g&gt;&lt;rect x="380" y="430" width="120" height="60" rx="9" ry="9" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 460px; margin-left: 381px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;&lt;div&gt;KeyCloak as&lt;/div&gt;&lt;div&gt;Identity Broker&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="440" y="464" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;KeyCloak as&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-66"&gt;&lt;g&gt;&lt;path d="M 519.45 464.19 L 519.34 474.69 L 500.5 459 L 519.65 443.7 L 519.55 454.2 L 580.55 454.81 L 580.66 444.31 L 599.5 460 L 580.35 475.3 L 580.45 464.8 Z" fill="#fff2cc" stroke="#d6b656" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-cell-id="MkZjjGYqzHr3rgLKbynL-67"&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 426px; margin-left: 551px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Other Protocol&lt;div&gt;(e.g. LDAP, SAML)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="551" y="429" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="11px" text-anchor="middle"&gt;Other Protocol&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Text is not SVG &amp;#8211; cannot display&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In essence, we need an OIDC client app and an authorization server. And I find the most simplistic test architecture to be pattern #2 (without reverse proxy) on the client side, and pattern #1 on the server side. In the next section let&amp;#8217;s discuss why I prefer this test architecture.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Choice of Tools&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The principle of this lab is that we can focus on the OIDC flows itself and simplify every other aspects as much as we can.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The authorization server needs to access my client app. As a result, if I use a public authorization server, such as Azure or Google, I&amp;#8217;d have to host my client app on a public IP with domain name as well. This creates churns. To see how much hassle this can involve, review my article &lt;a href="https://www.digihunch.com/2022/02/istio-external-authorization/"&gt;Istio External Authentication lab&lt;/a&gt;. Instead, I need a tool to host the authorization server on my laptop. And yes, it&amp;#8217;s &lt;a href="https://www.keycloak.org/"&gt;KeyCloak&lt;/a&gt;. It is a well-renewed open-source project for identity and access management. It is also the upstream project of &lt;a href="https://access.redhat.com/products/red-hat-single-sign-on"&gt;RedHat SSO&lt;/a&gt;. Another reason is it operates on PostgreSQL database which is a common relational database technology with release in Docker images.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the client side, we can have our web service with built-in OIDC capability, which usually requires development work in a language with OIDC library. Alternatively, if the client app lacks such capability, we would address this capability in a different component on the client side. It can either be a standalone, purpose-built proxy, or a generic reverse proxy with OIDC capability. For this, I examined a few options. &lt;a href="https://github.com/nginxinc/nginx-openid-connect"&gt;Nginx&lt;/a&gt; and &lt;a href="https://doc.traefik.io/traefik-enterprise/middlewares/oidc/"&gt;Traefik&lt;/a&gt; have OIDC support for a fee in their Enterprise product. Apache has a module &lt;a href="https://github.com/OpenIDC/mod_auth_openidc"&gt;mod_auth_oidc&lt;/a&gt; for free but it requires building the plug-in on my own for Mac platform. Eventually I landed on the purpose-built option, using the &lt;a href="https://github.com/oauth2-proxy/oauth2-proxy"&gt;oauth2-proxy&lt;/a&gt; open source project. This project can act as both actor #3 (with a minimal HTTP server) and actor #4 (OIDC client). So it also saves me from hosting a separate web server. Also, I have used it in the past in the &lt;a href="https://www.digihunch.com/2022/02/istio-external-authorization/"&gt;Istio External Authentication lab&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In reality, each message in the OIDC flows must be TLS encrypted. In local testing though we don&amp;#8217;t really care. Similarly we don&amp;#8217;t necessary need a reverse proxy if it plays no role in the OIDC flow. Both Keycloak (with PostgreSQL) and oauth2-proxy are released in Docker images. As a result, we are ready to roll with only three tools: the browser on local host, Keycloak and oauth2-proxy in the Docker daemon, which provides great portability.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To get started, let&amp;#8217;s have two fictitious domains, &lt;code&gt;web.digihunch.com&lt;/code&gt;, and &lt;code&gt;keycloak.digihunch.com&lt;/code&gt;. In the Docker compose manifest, I name the services based on their hostname so that they can reference each other from within the container network namespace. To access the service from the host, I force the DNS resolution to localhost in &lt;code&gt;/etc/hosts&lt;/code&gt; on my Mac, and make sure to declare the same host port in the port mapping (4180 for dummy web service; and 8080 for Keycloak).&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Configuration&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I created a Docker compose file as below, to set up my test:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;services&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;web.digihunch.com&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;oauth2-proxy&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;quay.io/oauth2-proxy/oauth2-proxy:latest&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;command&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - --&lt;span style="color:#ae81ff"&gt;http-address&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;0.0.0.0&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4180&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;environment&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_COOKIE_SECRET&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;NYZaClZinINKwxNGzEDeFGh64W6tmq1eB6uHQPa4S5o &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_CLIENT_ID&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;dh-user-client&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_CLIENT_SECRET&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;pmkwBjkVesrj7fw1MY7h5s9e3cmAKXgc &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_PROVIDER&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;oidc &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_OIDC_ISSUER_URL&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;http://keycloak.digihunch.com:8080/realms/digihunch-users&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_PASS_ACCESS_TOKEN&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_EMAIL_DOMAINS&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;*&amp;#39;&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_REDIRECT_URL&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;http://web.digihunch.com:4180/oauth2/callback&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_PROVIDER_DISPLAY_NAME&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;DHCKC&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_COOKIE_CSRF_EXPIRE&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;5m&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_COOKIE_CSRF_PER_REQUEST&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_COOKIE_SECURE&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Needed for HTTP connection&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#OAUTH2_PROXY_UPSTREAMS: file:///var/www/static/#/home/ # serve page at /home path&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;OAUTH2_PROXY_UPSTREAMS&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;static://202 &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;./config/oauth2-proxy.cfg:/etc/oauth2-proxy.cfg&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# - ./config/www:/var/www/static/&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;: &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;4180&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;4180&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;oidc_network&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;restart&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;unless-stopped&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;depends_on&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;keycloak.digihunch.com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;postgres-db&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;postgres&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;postgresdb&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;restart&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;always&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;shm_size&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;128mb&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;5432&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;5432&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;oidc_network&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;./data/pgdata:/var/lib/postgresql/data&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;environment&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;POSTGRES_USER=master&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;POSTGRES_PASSWORD=masterpass&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;POSTGRES_DB=keycloak&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;keycloak.digihunch.com&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;quay.io/keycloak/keycloak&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;command&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;start&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;environment&lt;/span&gt;: &lt;span style="color:#75715e"&gt;# Based on Hostname:v2 https://www.keycloak.org/docs/25.0.0/upgrading/#migrating-to-25-0-0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;KC_HOSTNAME&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;http://keycloak.digihunch.com:8080&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#KC_HOSTNAME_ADMIN: For simplicity, no separate management URL or port&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;KC_HOSTNAME_BACKCHANNEL_DYNAMIC&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;KC_HTTP_ENABLED&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; &lt;span style="color:#75715e"&gt;## Otherwise HTTPS is the enforced by default.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;KC_HEALTH_ENABLED&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;KEYCLOAK_ADMIN&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;admin &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;KEYCLOAK_ADMIN_PASSWORD&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;kcadminpass&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;KC_DB&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;postgres&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;KC_DB_URL&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;jdbc:postgresql://postgres-db/keycloak&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;KC_DB_USERNAME&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;master&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;KC_DB_PASSWORD&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;masterpass &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ports&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt;:&lt;span style="color:#ae81ff"&gt;8080&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;oidc_network&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;restart&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;always&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;depends_on&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;postgres-db&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;networks&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;oidc_network&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;enable_ipv6&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;driver&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;bridge&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;For OAuth2-Proxy, the &lt;a href="https://quay.io/repository/oauth2-proxy/oauth2-proxy"&gt;official image&lt;/a&gt; for oauth2-proxy is distroless. So if you have to troubleshoot its container file system, you need to access it via an &lt;a href="https://medium.com/@ananthsekar007/troubleshooting-strategies-for-distroless-containers-unveiling-solutions-in-minimalist-ca2e284b6e1a"&gt;assistant container&lt;/a&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run --rm -it --name debugger --privileged --pid container:oauth2-proxy --network container:oauth2-proxy busybox sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# to see target container&amp;#39;s file system, go to: ls -l /proc/1/root/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Alternatively, we can use the one that Bitnami &lt;a href="https://hub.docker.com/r/bitnami/oauth2-proxy/tags"&gt;releases&lt;/a&gt; but be vary of some &lt;a href="https://github.com/oauth2-proxy/oauth2-proxy/issues/1802#issuecomment-1447999568"&gt;nuances&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the Keycloak part, I use environment variables and had to watch out for the recent changes on &lt;a href="https://www.keycloak.org/docs/25.0.0/upgrading/#migrating-to-25-0-0"&gt;hostname v2&lt;/a&gt;. We should first start up the Keycloak service. From http://keycloak.digihunch.com:8080, we can login using the credential specified in the environment variables, then we can create a client app: &lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Create a new realm (dropdown-&amp;gt; Create realm) with name digihunch-users&lt;/li&gt;&#10;&lt;li&gt;Switch to this realm from the dropdown, create a couple users (e.g. dhadmin@www.digihunch.com), and set password.&lt;/li&gt;&#10;&lt;li&gt;Create a group (e.g. myadmin) and join the user to the group&lt;/li&gt;&#10;&lt;li&gt;Under the same realm, create a client, with OpenID Connect as type, client ID being dh-user-client. turn on client authentication (without Direct access grants)&lt;/li&gt;&#10;&lt;li&gt;Save the client for now and grab the client secret. Note that the OIDC discovery document (http://keycloak.digihunch.com:8080/realms/digihunch-users/.well-known/openid-configuration) should come online.&lt;/li&gt;&#10;&lt;li&gt;Update the docker compose file:&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;The value for OAUTH2_PROXY_CLIENT_SECRET is from the client secret; &lt;/li&gt;&#10;&lt;li&gt;The value for OAUTH2_PROXY_OIDC_ISSUER_URL should be http://keycloak.digihunch.com:8080/realms/digihunch-users; &lt;/li&gt;&#10;&lt;li&gt;The value for OAUTH2_PROXY_CLIENT_ID is dh-user-client;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Restart all services including the web. Log on to keycloak and go back to the client configuration in the realm. Under settings. Put in valid redirect URIs as http://web.digihunch.com:4180/oauth2/callback and save the client. &lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Now, let&amp;#8217;s start an private browser session, and browse to http://web.digihunch.com:4180/. The browser should redirect you to keycloak&amp;#8217;s login page. Once log in is successful, it should redirect you to the static response with 202 code as the manifest configured.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this post, I laid out the steps to test the login for OIDC authorization code flow locally as a starting point. For a bullet-proof solution, I recommend taking a look at KeyCloak &lt;a href="https://www.keycloak.org/docs/latest/server_admin/"&gt;administration guide&lt;/a&gt;. For example, we typically disable the master realm for security. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There is a similar test setup on &lt;a href="https://developer.okta.com/blog/2022/07/14/add-auth-to-any-app-with-oauth2-proxy"&gt;Otka blog&lt;/a&gt; but I simplified all the aspects that I regard as distractors. There are many other flows that can be tested. However, some of the testing still requires client pattern #1 if we need to initiates an activity from the client application.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://www.digihunch.com/2024/07/iam-roles-for-any-workload/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;IAM Roles for any workload&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://www.digihunch.com/2024/08/debating-between-count-and-for_each-in-terraform/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Debating between count and for_each in Terraform&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>