{"componentChunkName":"component---src-templates-tag-js","path":"/tags/oidc/","result":{"data":{"site":{"siteMetadata":{"title":"LoginRadius Blog"}},"allMarkdownRemark":{"totalCount":3,"edges":[{"node":{"fields":{"slug":"/engineering/implementing-oidc-sso-loginradius-as-identity-provider/"},"html":"<p>First, let's understand:</p>\n<ul>\n<li>What is SSO, and why should you use it?</li>\n<li>What is OIDC, and why is it used for authentication?</li>\n<li>How can you leverage LoginRadius as an identity provider?</li>\n</ul>\n<p><strong>SSO stands for Single Sign-On</strong>. It's an authentication process that allows a user to access multiple applications or systems with one set of login credentials (username and password). Instead of requiring users to log in separately to each application, SSO enables them to log in once and gain access to all the connected systems without needing to re-enter their credentials.</p>\n<p><strong>OpenID Connect (OIDC)</strong> is a protocol that builds on OAuth 2.0 to ensure secure user authentication and authorization. It adds an identity layer to OAuth 2.0, allowing applications to confirm a user's identity and gather basic profile information. OIDC utilizes JSON Web Tokens (JWTs) for these functions, aligning with OAuth 2.0's token acquisition methods. This integration enables seamless user authentication across different platforms, supporting features like single sign-on, where users can access multiple applications with one set of credentials managed by an identity provider.</p>\n<h2 id=\"what-is-loginradius-ciam\" style=\"position:relative;\"><a href=\"#what-is-loginradius-ciam\" aria-label=\"what is loginradius ciam permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is LoginRadius CIAM?</h2>\n<p>LoginRadius is a high-performance, scalable identity and access management platform focused on customer-facing use cases. It offers comprehensive features and capabilities to help you implement user authentication and authorization and manage user data with built-in workflows and security controls. </p>\n<p>On these lines, LoginRadius offers built-in support for OIDC and the use of OIDC to implement SSO.</p>\n<p>First, you need to create an OIDC application in LoginRadius to tailor user claim fields effortlessly. You can fine-tune these customizable user claims through LoginRadius' user-friendly interface. Subsequently, you can seamlessly integrate these claims into the token, enabling streamlined extraction and utilization within the application ecosystem.</p>\n<p>In essence, LoginRadius facilitates the setup of OIDC applications and offers customization capabilities through its intuitive interface. This ensures efficient management of user claims, ultimately contributing to a more personalized and secure authentication experience.</p>\n<p>After setting up the OIDC app from the LoginRadius dashboard, you'll use the <a href=\"https://github.com/coreos/go-oidc\"><code>go-oidc</code> library</a> to configure our provider further and configure the oidc connect.</p>\n<h2 id=\"setting-up-oidc-application-in-loginradius\" style=\"position:relative;\"><a href=\"#setting-up-oidc-application-in-loginradius\" aria-label=\"setting up oidc application in loginradius permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up OIDC Application in LoginRadius</h2>\n<p>Go to <a href=\"https://adminconsole.loginradius.com/platform-configuration/access-configuration/federated-sso/openid-connect\">OIDC Application Configuration</a> and click on <strong>Add App button</strong></p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 42.15384615384615%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHZsJIX/8QAFhABAQEAAAAAAAAAAAAAAAAAACIh/9oACAEBAAEFAqU1/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGhAAAgIDAAAAAAAAAAAAAAAAAAEhMTKBof/aAAgBAQAGPwKUtMx6Uf/EABgQAAMBAQAAAAAAAAAAAAAAAAABEfGh/9oACAEBAAE/IbwsCgT3P//aAAwDAQACAAMAAAAQf8//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAcEAEAAgEFAAAAAAAAAAAAAAABABFhIXGBkdH/2gAIAQEAAT8QByAsN7xidPIo1Jxn/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"OIDC App Configuration\"\n        title=\"OIDC App Configuration\"\n        src=\"/static/00116a4848c99cc03a6b816280de4dcd/212bf/OIDC-App.jpg\"\n        srcset=\"/static/00116a4848c99cc03a6b816280de4dcd/6aca1/OIDC-App.jpg 650w,\n/static/00116a4848c99cc03a6b816280de4dcd/212bf/OIDC-App.jpg 768w,\n/static/00116a4848c99cc03a6b816280de4dcd/e2c35/OIDC-App.jpg 2399w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>Enter the <strong>App name</strong> and click one of the following:</p>\n<p><strong>Native App</strong>, <strong>Single page App</strong> or <strong>Web App</strong> according to your application.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 54.769230769230774%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEAf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAW2RPIjA/8QAGRAAAwEBAQAAAAAAAAAAAAAAAQIDAAQR/9oACAEBAAEFAoIKMeeYGmxUmj+b/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGxAAAgEFAAAAAAAAAAAAAAAAAAExAhAhkaH/2gAIAQEABj8CaqXRzsgwTb//xAAaEAEAAgMBAAAAAAAAAAAAAAABABEQIVFB/9oACAEBAAE/IdAINVDEFw7lsMV1qOQ+eY//2gAMAwEAAgADAAAAEJDP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHRABAQABBAMAAAAAAAAAAAAAAREAITFBUWGB0f/aAAgBAQABPxBRRdUK2cZYtCXcC94Iao9mWkGHQefOVUChI+YbZ//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"OIDC App Setup\"\n        title=\"OIDC App Setup\"\n        src=\"/static/8a90565da5b70292e876657c74b5cf22/212bf/App-Setup.jpg\"\n        srcset=\"/static/8a90565da5b70292e876657c74b5cf22/6aca1/App-Setup.jpg 650w,\n/static/8a90565da5b70292e876657c74b5cf22/212bf/App-Setup.jpg 768w,\n/static/8a90565da5b70292e876657c74b5cf22/6f74a/App-Setup.jpg 2403w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>After clicking the <strong>Create</strong> button, you'll get the OIDC application configuration page. This page contains details like your application's <strong>Client ID</strong> and <strong>Client Secret</strong>, which are necessary for setting up the OIDC provider and configuration when you code in Golang.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 53.84615384615385%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHtawyhB//EABYQAAMAAAAAAAAAAAAAAAAAAAESIP/aAAgBAQABBQINX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABcQAAMBAAAAAAAAAAAAAAAAABEgIoH/2gAIAQEABj8CoY3/xAAYEAADAQEAAAAAAAAAAAAAAAAAARFREP/aAAgBAQABPyFdOdURT//aAAwDAQACAAMAAAAQg8//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAcEAEAAgEFAAAAAAAAAAAAAAABABEhEDFBccH/2gAIAQEAAT8QsNgvYSu7YU490ViPK8y0/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"OIDC APP Credentials\"\n        title=\"OIDC APP Credentials\"\n        src=\"/static/1461fbca24c61616613333e417d8ef5a/212bf/App-Credentials.jpg\"\n        srcset=\"/static/1461fbca24c61616613333e417d8ef5a/6aca1/App-Credentials.jpg 650w,\n/static/1461fbca24c61616613333e417d8ef5a/212bf/App-Credentials.jpg 768w,\n/static/1461fbca24c61616613333e417d8ef5a/e752a/App-Credentials.jpg 2389w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h4 id=\"upon-reaching-the-configuration-page-for-your-oidc-application-youll-encounter-a-variety-of-fields-ripe-for-customization\" style=\"position:relative;\"><a href=\"#upon-reaching-the-configuration-page-for-your-oidc-application-youll-encounter-a-variety-of-fields-ripe-for-customization\" aria-label=\"upon reaching the configuration page for your oidc application youll encounter a variety of fields ripe for customization permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Upon reaching the configuration page for your OIDC Application, you'll encounter a variety of fields ripe for customization:</h4>\n<ol>\n<li><strong>Algorithm</strong>: Presently, we offer support for <strong>rs256</strong>.</li>\n<li><strong>Grant Type</strong>: Options include authorization code, implicit, password creds, etc.</li>\n<li>You can tailor settings for <strong>Token Expiry</strong>, <strong>Refresh Token</strong>, and <strong>TTL</strong> to suit your needs.</li>\n<li><strong>Data Mapping</strong>: Define fields or properties to be included in the data response.</li>\n<li><strong>Metadata</strong>: Incorporate static, non-profile values into the data response.</li>\n<li>Define the Scope for Management API.</li>\n</ol>\n<p>This array of configurable options empowers you to fine-tune your OIDC Application according to your specific requirements.</p>\n<h2 id=\"whitelisting-the-domain-of-your-application\" style=\"position:relative;\"><a href=\"#whitelisting-the-domain-of-your-application\" aria-label=\"whitelisting the domain of your application permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Whitelisting the Domain of Your Application</h2>\n<p>To ensure seamless redirection of requests and successful callbacks to your endpoint, add your application's domain to the whitelist. This will authorize the redirection process and prevent failures when calling the callback endpoint.</p>\n<h4 id=\"to-access-web-apps-in-deployment-follow-these-steps\" style=\"position:relative;\"><a href=\"#to-access-web-apps-in-deployment-follow-these-steps\" aria-label=\"to access web apps in deployment follow these steps permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>To access Web Apps in Deployment, follow these steps:</h4>\n<ol>\n<li>Navigate to the Deployment section from the Dashboard.</li>\n<li>Once in Deployment, select the Apps tab.</li>\n<li>From there, choose Web Apps.</li>\n</ol>\n<h4 id=\"now-to-add-a-new-site\" style=\"position:relative;\"><a href=\"#now-to-add-a-new-site\" aria-label=\"now to add a new site permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Now, to add a new site:</h4>\n<ol>\n<li>Click on the <strong>Add New Site</strong> button.</li>\n<li>Enter the domain name of the website (example: \"<code>https://localhost:8080</code>\").</li>\n</ol>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 42.15384615384615%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHasEgV/8QAFxAAAwEAAAAAAAAAAAAAAAAAABAREv/aAAgBAQABBQKZVP/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABgQAAIDAAAAAAAAAAAAAAAAAAAxARCR/9oACAEBAAY/AnO0j//EABoQAAICAwAAAAAAAAAAAAAAAAABEVEhMYH/2gAIAQEAAT8hSZbLkcY2uf/aAAwDAQACAAMAAAAQCA//xAAWEQEBAQAAAAAAAAAAAAAAAAAAIRH/2gAIAQMBAT8Q2q//xAAVEQEBAAAAAAAAAAAAAAAAAAAQQf/aAAgBAgEBPxCH/8QAGhAAAgIDAAAAAAAAAAAAAAAAAREAITFhgf/aAAgBAQABPxBuBWVwceJcACgTc//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Whitelisting Domain Name\"\n        title=\"Whitelisting Domain Name\"\n        src=\"/static/831a186ed00cc5a79276211572734129/212bf/Whitelisting-Domain.jpg\"\n        srcset=\"/static/831a186ed00cc5a79276211572734129/6aca1/Whitelisting-Domain.jpg 650w,\n/static/831a186ed00cc5a79276211572734129/212bf/Whitelisting-Domain.jpg 768w,\n/static/831a186ed00cc5a79276211572734129/e2c35/Whitelisting-Domain.jpg 2399w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h3 id=\"whitelisting-domain-from-oidc-application-configuration\" style=\"position:relative;\"><a href=\"#whitelisting-domain-from-oidc-application-configuration\" aria-label=\"whitelisting domain from oidc application configuration permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Whitelisting Domain from OIDC Application Configuration</h3>\n<p>LoginRadius lets you uniquely identify the redirect URLs for individual OIDC applications:</p>\n<ul>\n<li>When setting the configuration of the OIDC Application, you can specify the redirect URL of your backend,\nand it will be whitelisted.</li>\n<li>The field name is <strong>Login Redirect URL</strong>.</li>\n</ul>\n<h2 id=\"setting-up-the-provider-object-and-the-oauthconfig-with-the-loginradius-oidc-app-credentials\" style=\"position:relative;\"><a href=\"#setting-up-the-provider-object-and-the-oauthconfig-with-the-loginradius-oidc-app-credentials\" aria-label=\"setting up the provider object and the oauthconfig with the loginradius oidc app credentials permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up the Provider Object and the OAuthconfig with the Loginradius OIDC App Credentials</h2>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk12\">provider</span><span class=\"mtk1\">, err := </span><span class=\"mtk12\">oidc</span><span class=\"mtk1\">.</span><span class=\"mtk11\">NewProvider</span><span class=\"mtk1\">(</span><span class=\"mtk12\">ctx</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;`https://api.loginradius.com/{oidcappname}&quot;</span><span class=\"mtk1\">)</span><span class=\"mtk8\">`</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">if err != nil {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">    // handle error</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">// Configure an OpenID Connect aware OAuth2 client.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">oauth2Config := oauth2.Config{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">    ClientID:     your-oidc-clientID,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">    ClientSecret: your-oidc-clientSecret</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">    RedirectURL:  redirectURL,</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">    // Discovery returns the OAuth2 endpoints.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">    Endpoint: provider.Endpoint(),</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">    // &quot;openid&quot; is a required scope for OpenID Connect flows.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">    Scopes: []string{oidc.ScopeOpenID, &quot;profile&quot;, &quot;email&quot;},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk8\">}</span></span></code></pre>\n<p>When setting up a new provider, you'll need to input the LoginRadius OIDC App URL, typically in this format: <code>https://{siteUrl}/service/oidc/{OidcAppName}</code></p>\n<p>To seamlessly integrate this with your Go backend, create two essential APIs for setting up and configuring <code>go-oidc</code>:</p>\n<ol>\n<li><strong>Login Endpoint</strong>: This endpoint initiates the authentication process and redirects to the callback endpoint with the authorization code.</li>\n<li><strong>Callback Endpoint</strong>: Here, the authorization code received from the login endpoint is exchanged for an access token. Additionally, this endpoint extracts user claims from the access token.</li>\n</ol>\n<p>By establishing these APIs, your Go backend efficiently handles the authentication flow, ensuring a smooth user experience while securely managing user identity and access.</p>\n<h2 id=\"handle-the-callback-hit\" style=\"position:relative;\"><a href=\"#handle-the-callback-hit\" aria-label=\"handle the callback hit permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Handle the Callback Hit</h2>\n<p>Handle the callback hit that exchanged the authorization token for the access token:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">verifier</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">provider</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Verifier</span><span class=\"mtk1\">(&</span><span class=\"mtk12\">oidc</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Config</span><span class=\"mtk1\">{</span><span class=\"mtk12\">ClientID:</span><span class=\"mtk1\"> </span><span class=\"mtk12\">clientID</span><span class=\"mtk1\">})</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">func</span><span class=\"mtk1\"> </span><span class=\"mtk11\">handleOAuth2Callback</span><span class=\"mtk1\">(</span><span class=\"mtk12\">ctx</span><span class=\"mtk1\"> *</span><span class=\"mtk12\">gin</span><span class=\"mtk1\">.</span><span class=\"mtk12\">context</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">// Verify state and errors.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    authCode := </span><span class=\"mtk12\">ctx</span><span class=\"mtk1\">.</span><span class=\"mtk11\">query</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;code&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">oauth2Token</span><span class=\"mtk1\">, err := </span><span class=\"mtk12\">oauth2Config</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Exchange</span><span class=\"mtk1\">(</span><span class=\"mtk12\">ctx</span><span class=\"mtk1\">, </span><span class=\"mtk12\">authCode</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk12\">err</span><span class=\"mtk1\"> != </span><span class=\"mtk12\">nil</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\">// handle error</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">// Extract the ID Token from the OAuth2 token.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">rawIDToken</span><span class=\"mtk1\">, ok := </span><span class=\"mtk12\">oauth2Token</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Extra</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;id_token&quot;</span><span class=\"mtk1\">).(</span><span class=\"mtk12\">string</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> !</span><span class=\"mtk12\">ok</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\">// handle missing token</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">// Parse and verify ID Token payload.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">idToken</span><span class=\"mtk1\">, err := </span><span class=\"mtk12\">verifier</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Verify</span><span class=\"mtk1\">(</span><span class=\"mtk12\">ctx</span><span class=\"mtk1\">, </span><span class=\"mtk12\">rawIDToken</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk12\">err</span><span class=\"mtk1\"> != </span><span class=\"mtk12\">nil</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\">// handle error</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">// Extract custom claims</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">claims</span><span class=\"mtk1\"> struct {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">Email</span><span class=\"mtk1\">    </span><span class=\"mtk12\">string</span><span class=\"mtk1\"> </span><span class=\"mtk8\">`json:&quot;email&quot;`</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">Verified</span><span class=\"mtk1\"> </span><span class=\"mtk12\">bool</span><span class=\"mtk1\">   </span><span class=\"mtk8\">`json:&quot;email_verified&quot;`</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> err := </span><span class=\"mtk12\">idToken</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Claims</span><span class=\"mtk1\">(&</span><span class=\"mtk12\">claims</span><span class=\"mtk1\">); </span><span class=\"mtk12\">err</span><span class=\"mtk1\"> != </span><span class=\"mtk12\">nil</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\">// handle error</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>For both endpoints, let's review a sample backend server with implementation in <a href=\"https://github.com/gin-gonic/gin\">Gin Golang</a>.</p>\n<h2 id=\"gin-golang-code\" style=\"position:relative;\"><a href=\"#gin-golang-code\" aria-label=\"gin golang code permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Gin Golang Code</h2>\n<p>For OIDC integration with the Go backend, you'll implement it using the <a href=\"https://github.com/coreos/go-oidc\">coreos/go-oidc</a> library (feel free to check it out). This library provides comprehensive support for OIDC, allowing to easily verify tokens, extract user claims, and validate ID tokens. Its features ensure secure authentication and seamless integration with various OIDC providers.</p>\n<p>With the <code>go-oidc</code> library, you can efficiently implement OIDC authentication in the Go backend, guaranteeing users a smooth and secure authentication process.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">go get github.com/coreos/go-oidc/v3/oidc</span></span></code></pre>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">package</span><span class=\"mtk1\"> </span><span class=\"mtk12\">main</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">import</span><span class=\"mtk1\"> (</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk8\">&quot;encoding/json&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk8\">&quot;fmt&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk8\">&quot;io&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk8\">&quot;log&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk8\">&quot;net/http&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk8\">&quot;os&quot;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk8\">&quot;github.com/coreos/go-oidc/v3/oidc&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk8\">&quot;github.com/gin-gonic/gin&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk8\">&quot;golang.org/x/oauth2&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Define global OAuth2 configuration and OIDC provider.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> (</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">oauthConfig</span><span class=\"mtk1\"> = &</span><span class=\"mtk12\">oauth2</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Config</span><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\tClientID:     </span><span class=\"mtk8\">&quot;your-client-id&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk3\">// Replace with your LoginRadius Client ID</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\tRedirectURL:  </span><span class=\"mtk8\">&quot;http://localhost:8080/api/callback&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\tClientSecret: </span><span class=\"mtk8\">&quot;your-client-secret&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk3\">// Replace with your LoginRadius Client Secret</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\tScopes:       []</span><span class=\"mtk12\">string</span><span class=\"mtk1\">{</span><span class=\"mtk8\">&quot;user&quot;</span><span class=\"mtk1\">},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">globalProvider</span><span class=\"mtk1\">   *</span><span class=\"mtk12\">oidc</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Provider</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">globalOuthConfig</span><span class=\"mtk1\"> *</span><span class=\"mtk12\">oauth2</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Config</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Server struct holds interfaces like HTTP server, DBHelper, ServerProvider, MongoDB client, etc.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">type</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Server</span><span class=\"mtk1\"> struct {</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// InitializeOAuthConfig sets up the global OAuth2 configuration and OIDC provider.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">func</span><span class=\"mtk1\"> </span><span class=\"mtk11\">InitializeOAuthConfig</span><span class=\"mtk1\">() {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Create a new OIDC provider using the OAuth2 endpoint and OIDC provider URL.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">provider</span><span class=\"mtk1\">, err := </span><span class=\"mtk12\">oidc</span><span class=\"mtk1\">.</span><span class=\"mtk11\">NewProvider</span><span class=\"mtk1\">(</span><span class=\"mtk12\">context</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Background</span><span class=\"mtk1\">(), </span><span class=\"mtk8\">&quot;https://&lt;siteUrl&gt;/service/oidc/&lt;OidcAppName&gt;&quot;</span><span class=\"mtk1\">) </span><span class=\"mtk3\">// Replace with your OIDC Provider URL</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk12\">err</span><span class=\"mtk1\">!= </span><span class=\"mtk12\">nil</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk12\">log</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Fatalf</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Failed to create new provider: %v&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">err</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">globalProvider</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">provider</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Set up the OAuth2 configuration with the client ID, secret, redirect URL, and scopes.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\toauth2Config := &</span><span class=\"mtk12\">oauth2</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Config</span><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\tClientID:     </span><span class=\"mtk12\">oauthConfig</span><span class=\"mtk1\">.</span><span class=\"mtk12\">ClientID</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\tClientSecret: </span><span class=\"mtk12\">oauthConfig</span><span class=\"mtk1\">.</span><span class=\"mtk12\">ClientSecret</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\tRedirectURL:  </span><span class=\"mtk12\">oauthConfig</span><span class=\"mtk1\">.</span><span class=\"mtk12\">RedirectURL</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\tEndpoint:     </span><span class=\"mtk12\">provider</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Endpoint</span><span class=\"mtk1\">(),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\tScopes:       []</span><span class=\"mtk12\">string</span><span class=\"mtk1\">{</span><span class=\"mtk12\">oidc</span><span class=\"mtk1\">.</span><span class=\"mtk12\">ScopeOpenID</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;profile&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;email&quot;</span><span class=\"mtk1\">},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">globalOuthConfig</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">oauth2Config</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// StartLoginProcess initiates the login process by redirecting the user to the OIDC provider.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">func</span><span class=\"mtk1\"> </span><span class=\"mtk11\">StartLoginProcess</span><span class=\"mtk1\">(</span><span class=\"mtk12\">ctx</span><span class=\"mtk1\"> *</span><span class=\"mtk12\">gin</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Context</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Generate the authorization URL for the OIDC provider.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\tauthURL := </span><span class=\"mtk12\">globalOuthConfig</span><span class=\"mtk1\">.</span><span class=\"mtk11\">AuthCodeURL</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;state&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">oidc</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Nonce</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Redirect the user to the OIDC provider for authentication.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">http</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Redirect</span><span class=\"mtk1\">(</span><span class=\"mtk12\">ctx</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Writer</span><span class=\"mtk1\">, </span><span class=\"mtk12\">ctx</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Request</span><span class=\"mtk1\">, </span><span class=\"mtk12\">authURL</span><span class=\"mtk1\">, </span><span class=\"mtk12\">http</span><span class=\"mtk1\">.</span><span class=\"mtk12\">StatusFound</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// HandleCallback processes the callback from the OIDC provider after the user has authenticated.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">func</span><span class=\"mtk1\"> </span><span class=\"mtk11\">HandleCallback</span><span class=\"mtk1\">(</span><span class=\"mtk12\">ctx</span><span class=\"mtk1\"> *</span><span class=\"mtk12\">gin</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Context</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Retrieve the authorization code from the query parameters.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\tcode := </span><span class=\"mtk12\">ctx</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Query</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;code&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Exchange the authorization code for an access token.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">oauth2Token</span><span class=\"mtk1\">, err := </span><span class=\"mtk12\">globalOuthConfig</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Exchange</span><span class=\"mtk1\">(</span><span class=\"mtk12\">ctx</span><span class=\"mtk1\">, </span><span class=\"mtk12\">code</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk12\">err</span><span class=\"mtk1\">!= </span><span class=\"mtk12\">nil</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk12\">log</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Printf</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Error exchanging code for token: %v&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">err</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Extract the ID token from the OAuth2 token.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">rawIDToken</span><span class=\"mtk1\">, ok := </span><span class=\"mtk12\">oauth2Token</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Extra</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;id_token&quot;</span><span class=\"mtk1\">).(</span><span class=\"mtk12\">string</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk15\">if</span><span class=\"mtk1\">!</span><span class=\"mtk12\">ok</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk12\">log</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Println</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Missing ID token&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Verify the ID token using the OIDC provider.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">verifier</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">globalProvider</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Verifier</span><span class=\"mtk1\">(&</span><span class=\"mtk12\">oidc</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Config</span><span class=\"mtk1\">{</span><span class=\"mtk12\">ClientID:</span><span class=\"mtk1\"> </span><span class=\"mtk12\">globalOuthConfig</span><span class=\"mtk1\">.</span><span class=\"mtk12\">ClientID</span><span class=\"mtk1\">, </span><span class=\"mtk12\">SkipClientIDCheck:</span><span class=\"mtk1\"> </span><span class=\"mtk4\">true</span><span class=\"mtk1\">})</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">idToken</span><span class=\"mtk1\">, err := </span><span class=\"mtk12\">verifier</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Verify</span><span class=\"mtk1\">(</span><span class=\"mtk12\">ctx</span><span class=\"mtk1\">, </span><span class=\"mtk12\">rawIDToken</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk12\">err</span><span class=\"mtk1\">!= </span><span class=\"mtk12\">nil</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk12\">log</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Printf</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Error verifying ID token: %v&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">err</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Extract claims from the verified ID token.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">claims</span><span class=\"mtk1\"> interface{}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk15\">if</span><span class=\"mtk1\"> err := </span><span class=\"mtk12\">idToken</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Claims</span><span class=\"mtk1\">(&</span><span class=\"mtk12\">claims</span><span class=\"mtk1\">); </span><span class=\"mtk12\">err</span><span class=\"mtk1\">!= </span><span class=\"mtk12\">nil</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk12\">log</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Printf</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Error extracting claims: %v&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">err</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Respond with a success message.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">ctx</span><span class=\"mtk1\">.</span><span class=\"mtk11\">JSON</span><span class=\"mtk1\">(</span><span class=\"mtk12\">http</span><span class=\"mtk1\">.</span><span class=\"mtk12\">StatusOK</span><span class=\"mtk1\">, </span><span class=\"mtk12\">gin</span><span class=\"mtk1\">.</span><span class=\"mtk12\">H</span><span class=\"mtk1\">{</span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;success&quot;</span><span class=\"mtk1\">})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// InjectRoutes sets up the routes for the application, including login and callback endpoints.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">func</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">srv</span><span class=\"mtk1\"> *</span><span class=\"mtk10\">Server</span><span class=\"mtk1\">) </span><span class=\"mtk11\">InjectRoutes</span><span class=\"mtk1\">() *</span><span class=\"mtk12\">gin</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Engine</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\trouter := </span><span class=\"mtk12\">gin</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Default</span><span class=\"mtk1\">()</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\tapi := </span><span class=\"mtk12\">router</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Group</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/api&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk3\">// Define the login route that redirects users to the OIDC provider for authentication.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk12\">api</span><span class=\"mtk1\">.</span><span class=\"mtk11\">GET</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/login&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">StartLoginProcess</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk3\">// Define the callback route that handles the callback from the OIDC provider.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t\t</span><span class=\"mtk12\">api</span><span class=\"mtk1\">.</span><span class=\"mtk11\">GET</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/callback&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">HandleCallback</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">router</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">func</span><span class=\"mtk1\"> </span><span class=\"mtk11\">main</span><span class=\"mtk1\">() {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Initialize the OAuth2 configuration and OIDC provider.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk11\">InitializeOAuthConfig</span><span class=\"mtk1\">()</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Create a new server instance.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\tserver := &</span><span class=\"mtk10\">Server</span><span class=\"mtk1\">{}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Inject routes into the Gin engine.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\trouter := </span><span class=\"mtk12\">server</span><span class=\"mtk1\">.</span><span class=\"mtk11\">InjectRoutes</span><span class=\"mtk1\">()</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk3\">// Start the HTTP server.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">\t</span><span class=\"mtk12\">log</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Fatal</span><span class=\"mtk1\">(</span><span class=\"mtk12\">http</span><span class=\"mtk1\">.</span><span class=\"mtk11\">ListenAndServe</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;:8080&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">router</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>The process described involves several key steps in setting up an OAuth2 flow with OpenID Connect (OIDC) for user authentication.</p>\n<p>Here's a brief overview of what was done in the code:</p>\n<h3 id=\"initialization-of-oidc-provider-and-oauth2-configuration\" style=\"position:relative;\"><a href=\"#initialization-of-oidc-provider-and-oauth2-configuration\" aria-label=\"initialization of oidc provider and oauth2 configuration permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Initialization of OIDC Provider and OAuth2 Configuration</h3>\n<ul>\n<li>The OIDC provider is initialized using the <code>oidc.NewProvider</code> function, which requires the OAuth2 endpoint and the OIDC provider's URL. This step is crucial for establishing a connection with the OIDC provider, enabling the application to authenticate users through the provider.</li>\n<li>The OAuth2 configuration (<code>oauthConfig</code>) is set up with essential details such as the client ID, client secret, redirect URL, and scopes. These credentials are specific to the OIDC application registered with the provider (e.g., LoginRadius). The redirect URL is where the provider will send the user after authentication, and the scopes define the permissions requested from the user.</li>\n</ul>\n<h3 id=\"setting-up-the-callback-endpoint\" style=\"position:relative;\"><a href=\"#setting-up-the-callback-endpoint\" aria-label=\"setting up the callback endpoint permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up the Callback Endpoint</h3>\n<ul>\n<li>A callback endpoint is defined in the application, typically as <code>/api/callback</code>. This endpoint handles the callback from the OIDC provider after the user has been authenticated.</li>\n<li>When the user authenticates successfully, the OIDC provider redirects the user back to the application with an authorization code included in the query parameters.</li>\n<li>The application then exchanges this authorization code for an access token by calling the exchange method on the OAuth2 configuration object. This exchange process is handled securely by the OAuth2 library, ensuring that the application receives a valid access token.</li>\n</ul>\n<h3 id=\"verifying-the-access-token-and-extracting-user-claims\" style=\"position:relative;\"><a href=\"#verifying-the-access-token-and-extracting-user-claims\" aria-label=\"verifying the access token and extracting user claims permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Verifying the Access Token and Extracting User Claims</h3>\n<ul>\n<li>Once the access token is obtained, the application extracts the ID token from it. The ID token contains claims about the authenticated user, such as their name, email, and roles.</li>\n<li>The ID token is then verified using the OIDC provider's verifier. This step ensures that the token is valid and has not been tampered with. Verification involves checking the token's signature and possibly other claims to ensure it matches the expected values.</li>\n<li>After verification, the application extracts the claims from the ID token. These claims can be used to identify the user within the application, personalize the user experience, or enforce access control based on the user's roles or permissions.</li>\n</ul>\n<p>This process leverages the security and standardization provided by OIDC and OAuth2 to implement a secure authentication flow. By following these steps, the application can authenticate users through LoginRadius OIDC provider, ensuring that user credentials are managed securely and that the application can trust authenticated users' identities.</p>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>In this tutorial, you have learned how to implement OIDC SSO with LoginRadius as the Identity Provider. You have also built a simple Golang backend with Gin to understand the implementation.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n</style>","frontmatter":{"date":"May 30, 2024","updated_date":null,"title":"How to Implement OpenID Connect (OIDC) SSO with LoginRadius?","tags":["SSO","OIDC","LoginRadius"],"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/4509bd963b39d84ce554829099fba02f/ee604/implementing-oidc-sso.png","srcSet":"/static/4509bd963b39d84ce554829099fba02f/69585/implementing-oidc-sso.png 200w,\n/static/4509bd963b39d84ce554829099fba02f/497c6/implementing-oidc-sso.png 400w,\n/static/4509bd963b39d84ce554829099fba02f/ee604/implementing-oidc-sso.png 800w,\n/static/4509bd963b39d84ce554829099fba02f/f3583/implementing-oidc-sso.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Sanjay Velu","github":"SanjayV0","avatar":null}}}},{"node":{"fields":{"slug":"/engineering/guest-post/add-authentication-to-play-framework-with-oidc-and-loginradius/"},"html":"<p>In this blog post, I will write a step-by-step tutorial to add Authentication to the Play Framework Application with OIDC and LoginRadius. I will be using <a href=\"http://www.pac4j.org/\">pac4j</a> and it's <a href=\"https://github.com/pac4j/play-pac4j\">play-pac4j</a> integration in this tutorial. Before jumping into the tutorial, let's learn about few concepts. </p>\n<h2 id=\"what-is-openid-connect-oidc-protocol\" style=\"position:relative;\"><a href=\"#what-is-openid-connect-oidc-protocol\" aria-label=\"what is openid connect oidc protocol permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is OpenID Connect (OIDC) Protocol?</h2>\n<p>OIDC is an authentication protocol that allows users to verify their identity when they are trying to access a protected HTTPS endpoint. OIDC is an evolutionary development of ideas implemented earlier in OAuth and OpenID.</p>\n<p>OpenID Connect allows clients to request and receive information about authenticated sessions and end-users. It allows all types of clients, including </p>\n<ul>\n<li>Web-based</li>\n<li>Mobile</li>\n<li>Javascript clients etc...</li>\n</ul>\n<p>You can find out more details about <a href=\"https://openid.net/connect/\">OIDC here</a></p>\n<h2 id=\"what-is-play-framework\" style=\"position:relative;\"><a href=\"#what-is-play-framework\" aria-label=\"what is play framework permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is Play Framework?</h2>\n<p>Play Framework is an open-source web application framework that follows the model–view–controller architectural pattern. It is written in Scala and usable from other programming languages that are compiled to JVM Bytecode.</p>\n<p>It makes it easy to build web applications with Java &#x26; Scala. Play is based on a lightweight, stateless, web-friendly architecture. Built on Akka, Play provides predictable and minimal resource consumption (CPU, memory, threads) for highly-scalable applications.</p>\n<h2 id=\"what-is-pac4j\" style=\"position:relative;\"><a href=\"#what-is-pac4j\" aria-label=\"what is pac4j permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is pac4j?</h2>\n<p><a href=\"http://www.pac4j.org/\">pac4j</a> is an easy and powerful security engine for Java to authenticate users, get their profiles and manage authorizations in order to secure web applications and web services.</p>\n<p>It provides a comprehensive set of concepts and components. It is based on Java and available under the Apache 2 license. It is available for most frameworks/tools and supports most authentication/authorization mechanisms.</p>\n<p>pac4j is supported with most of the Java frameworks like</p>\n<ul>\n<li>Spring Web MVC </li>\n<li>Spring Boot </li>\n<li>Spring Security (Spring Boot) </li>\n<li>Play 2.x </li>\n<li>Vertx Spark Java </li>\n<li>Javalin  </li>\n<li>Dropwizard </li>\n<li>Lagom </li>\n<li>Akka HTTP &#x26; many more...</li>\n</ul>\n<h2 id=\"getting-started\" style=\"position:relative;\"><a href=\"#getting-started\" aria-label=\"getting started permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Getting started</h2>\n<p>There are multiple options you can get started with the Play framework. </p>\n<ul>\n<li>You can create a new Play project by downloading the <a href=\"https://playframework.com/download#starters\">starter project here</a></li>\n<li>Create a new Play application using <code>sbt</code>.</li>\n</ul>\n<p>For this tutorial, I will be using creating a new play project using <code>sbt</code>.</p>\n<h3 id=\"install-sbt-on-mac-os\" style=\"position:relative;\"><a href=\"#install-sbt-on-mac-os\" aria-label=\"install sbt on mac os permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Install sbt on Mac OS</h3>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"console\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">brew install sbt</span></code></pre>\n<p>You can find <a href=\"https://www.scala-sbt.org/release/docs/Setup.html\">Installation steps for Windows and Linux</a> here.</p>\n<h3 id=\"prerequisites\" style=\"position:relative;\"><a href=\"#prerequisites\" aria-label=\"prerequisites permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Prerequisites</h3>\n<p>For this tutorial, I will be using </p>\n<ul>\n<li>Java 11</li>\n<li>sbt - 1.5.3</li>\n<li>play-pac4j - 11.0.0-PLAY2.8</li>\n<li>pac4j-oidc - 5.1.0</li>\n</ul>\n<h2 id=\"create-new-play-project\" style=\"position:relative;\"><a href=\"#create-new-play-project\" aria-label=\"create new play project permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Create New Play Project</h2>\n<p>Create a new java play project using the following command</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"console\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">sbt new playframework/play-java-seed.g8</span></code></pre>\n<p>The above command will prompt you to fill in the project <code>name</code> and project package structure in <code>organization</code> as shown below.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"console\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">[info] welcome to sbt 1.5.3 (Oracle Corporation Java 11.0.2)</span>\n<span class=\"grvsc-line\">[info] set current project to new (in build file:/private/var/folders/_9/rcqwq2vx1cl_1sc4xdhb5_5c0000gn/T/sbt_661d1bf7/new/)</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">This template generates a Play Java project</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">name [play-java-seed]: loginradius-play-oidc</span>\n<span class=\"grvsc-line\">organization [com.example]: com.loginradius.developer</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">Template applied in /Users/vishnuchilamakuru/self/longinradius/./loginradius-play-oidc</span></code></pre>\n<h2 id=\"run-play-project\" style=\"position:relative;\"><a href=\"#run-play-project\" aria-label=\"run play project permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Run Play Project</h2>\n<p>Now that the project is created with a base template. You can test it by running the project using the following command from <code>loginradius-play-oidc</code> folder.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"console\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">sbt run</span></code></pre>\n<p>Now visit <code>http://localhost:9000</code>, and it should look like this.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 55.53846153846153%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAvUlEQVQoz+WPUQuDIBSF/f//bODDKBZNM22SL5WxoIiozlLWnlassbcdOFzRez/PJfx8AuUUqZaQUiFNJfLcwNY1rLVQN42IJUhkBiYUrkKCpwpsw6RtW3RdB1eHYUDf9xjH0d85YFVVvhZF4X1vGkzT5HvemcRxDCEElMpgjIHWGpcoQlmWmOfZD78Az/OeCeccYRgiCAIwxhawAqV0WTuHk4MeEdl7dLCjJlvR12Rr48cJ9377+crf6A+BD5SBXJjm2F2yAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"play-project-homepage.png\"\n        title=\"play-project-homepage.png\"\n        src=\"/static/98136bf03eb0d8319d556f6a7ba1237c/e5715/play-project-homepage.png\"\n        srcset=\"/static/98136bf03eb0d8319d556f6a7ba1237c/a6d36/play-project-homepage.png 650w,\n/static/98136bf03eb0d8319d556f6a7ba1237c/e5715/play-project-homepage.png 768w,\n/static/98136bf03eb0d8319d556f6a7ba1237c/ccf0c/play-project-homepage.png 1428w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h2 id=\"integrate-pac4j-with-play-project\" style=\"position:relative;\"><a href=\"#integrate-pac4j-with-play-project\" aria-label=\"integrate pac4j with play project permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Integrate pac4j with Play Project</h2>\n<h3 id=\"1-add-pac4j-dependencies-to-buildsbt\" style=\"position:relative;\"><a href=\"#1-add-pac4j-dependencies-to-buildsbt\" aria-label=\"1 add pac4j dependencies to buildsbt permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. Add pac4j dependencies to <code>build.sbt</code></h3>\n<p>Add pac4j dependencies, Java 11 as required, and target version to compile the project in <code>build.sbt</code>.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">name := &quot;&quot;&quot;loginradius-play-oidc&quot;&quot;&quot;</span>\n<span class=\"grvsc-line\">organization := &quot;com.loginradius.developer&quot;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">version := &quot;1.0-SNAPSHOT&quot;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">lazy val root = (project in file(&quot;.&quot;)).enablePlugins(PlayJava)</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">scalaVersion := &quot;2.13.6&quot;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">initialize := {</span>\n<span class=\"grvsc-line\">  val _ = initialize.value // run the previous initialization</span>\n<span class=\"grvsc-line\">  val required = &quot;11&quot;</span>\n<span class=\"grvsc-line\">  val current  = sys.props(&quot;java.specification.version&quot;)</span>\n<span class=\"grvsc-line\">  assert(current == required, s&quot;Unsupported JDK: java.specification.version $current != $required&quot;)</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">scalacOptions += &quot;-target:jvm-11&quot;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">javacOptions ++= Seq(&quot;-source&quot;, &quot;11&quot;, &quot;-target&quot;, &quot;11&quot;)</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">libraryDependencies ++= Seq(</span>\n<span class=\"grvsc-line\">  guice,</span>\n<span class=\"grvsc-line\">  ehcache,</span>\n<span class=\"grvsc-line\">  &quot;org.pac4j&quot; %% &quot;play-pac4j&quot; % &quot;11.0.0-PLAY2.8&quot;,</span>\n<span class=\"grvsc-line\">  &quot;org.pac4j&quot; % &quot;pac4j-oidc&quot; % &quot;5.1.0&quot;,</span>\n<span class=\"grvsc-line\">  &quot;com.typesafe.play&quot; % &quot;play-cache_2.13&quot; % &quot;2.8.8&quot;,</span>\n<span class=\"grvsc-line\">  &quot;com.fasterxml.jackson.module&quot; %% &quot;jackson-module-scala&quot; % &quot;2.12.3&quot;</span>\n<span class=\"grvsc-line\">)</span></code></pre>\n<h3 id=\"2-create-security-module\" style=\"position:relative;\"><a href=\"#2-create-security-module\" aria-label=\"2 create security module permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2. Create Security Module</h3>\n<p>Create <code>app/modules/SecurityModule.java</code>. This class configures OIDC, sets up a secure HttpActionAdapter, and registers callback and logout controllers.</p>\n<ul>\n<li>SecurityModule.java</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"java\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">package</span><span class=\"mtk1\"> modules;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> com.google.inject.AbstractModule;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> com.nimbusds.oauth2.sdk.ParseException;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> com.typesafe.config.Config;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> net.minidev.json.JSONObject;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.core.authorization.authorizer.RequireAnyRoleAuthorizer;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.core.client.Clients;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.core.context.session.SessionStore;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.oidc.client.OidcClient;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.oidc.config.OidcConfiguration;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.play.CallbackController;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.play.LogoutController;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.play.http.PlayHttpActionAdapter;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.play.store.PlayCacheSessionStore;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> play.Environment;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> java.util.Optional;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">public</span><span class=\"mtk1\"> </span><span class=\"mtk4\">class</span><span class=\"mtk1\"> </span><span class=\"mtk10\">SecurityModule</span><span class=\"mtk1\"> </span><span class=\"mtk4\">extends</span><span class=\"mtk1\"> </span><span class=\"mtk10\">AbstractModule</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">private</span><span class=\"mtk1\"> </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Config</span><span class=\"mtk1\"> </span><span class=\"mtk12\">configuration</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> </span><span class=\"mtk11\">SecurityModule</span><span class=\"mtk1\">(</span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Environment</span><span class=\"mtk1\"> </span><span class=\"mtk12\">environment</span><span class=\"mtk1\">, </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Config</span><span class=\"mtk1\"> </span><span class=\"mtk12\">configuration</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">configuration</span><span class=\"mtk1\"> = configuration;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    @</span><span class=\"mtk10\">Override</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">protected</span><span class=\"mtk1\"> </span><span class=\"mtk10\">void</span><span class=\"mtk1\"> </span><span class=\"mtk11\">configure</span><span class=\"mtk1\">() {</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">bind</span><span class=\"mtk1\">(</span><span class=\"mtk12\">SessionStore</span><span class=\"mtk1\">.</span><span class=\"mtk12\">class</span><span class=\"mtk1\">).</span><span class=\"mtk11\">to</span><span class=\"mtk1\">(</span><span class=\"mtk12\">PlayCacheSessionStore</span><span class=\"mtk1\">.</span><span class=\"mtk12\">class</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">OidcConfiguration</span><span class=\"mtk1\"> </span><span class=\"mtk12\">oidcConfiguration</span><span class=\"mtk1\"> = </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> </span><span class=\"mtk11\">OidcConfiguration</span><span class=\"mtk1\">();</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">oidcConfiguration</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setDiscoveryURI</span><span class=\"mtk1\">(</span><span class=\"mtk12\">configuration</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getString</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;oidc.discoveryUri&quot;</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">oidcConfiguration</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setClientId</span><span class=\"mtk1\">(</span><span class=\"mtk12\">configuration</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getString</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;oidc.clientId&quot;</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">oidcConfiguration</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setSecret</span><span class=\"mtk1\">(</span><span class=\"mtk12\">configuration</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getString</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;oidc.clientSecret&quot;</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">oidcConfiguration</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setClientAuthenticationMethod</span><span class=\"mtk1\">(</span><span class=\"mtk12\">ClientAuthenticationMethod</span><span class=\"mtk1\">.</span><span class=\"mtk12\">CLIENT_SECRET_BASIC</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">addProviderMetadata</span><span class=\"mtk1\">(oidcConfiguration);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">OidcClient</span><span class=\"mtk1\"> </span><span class=\"mtk12\">oidcClient</span><span class=\"mtk1\"> = </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> </span><span class=\"mtk11\">OidcClient</span><span class=\"mtk1\">(oidcConfiguration);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">oidcClient</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addAuthorizationGenerator</span><span class=\"mtk1\">((ctx, session, profile) </span><span class=\"mtk4\">-&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk12\">profile</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addRole</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;ROLE_ADMIN&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">Optional</span><span class=\"mtk1\">.</span><span class=\"mtk11\">of</span><span class=\"mtk1\">(profile);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        });</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">String</span><span class=\"mtk1\"> </span><span class=\"mtk12\">baseUrl</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">configuration</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getString</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;baseUrl&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Clients</span><span class=\"mtk1\"> </span><span class=\"mtk12\">clients</span><span class=\"mtk1\"> = </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> </span><span class=\"mtk11\">Clients</span><span class=\"mtk1\">(baseUrl + </span><span class=\"mtk8\">&quot;/callback&quot;</span><span class=\"mtk1\">,  oidcClient);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">org</span><span class=\"mtk1\">.</span><span class=\"mtk10\">pac4j</span><span class=\"mtk1\">.</span><span class=\"mtk10\">core</span><span class=\"mtk1\">.</span><span class=\"mtk10\">config</span><span class=\"mtk1\">.</span><span class=\"mtk10\">Config</span><span class=\"mtk1\"> </span><span class=\"mtk12\">config</span><span class=\"mtk1\"> = </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> org.pac4j.core.config.</span><span class=\"mtk11\">Config</span><span class=\"mtk1\">(clients);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">config</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addAuthorizer</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;admin&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> </span><span class=\"mtk11\">RequireAnyRoleAuthorizer</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;ROLE_ADMIN&quot;</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">config</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setHttpActionAdapter</span><span class=\"mtk1\">(</span><span class=\"mtk12\">PlayHttpActionAdapter</span><span class=\"mtk1\">.</span><span class=\"mtk12\">INSTANCE</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">bind</span><span class=\"mtk1\">(</span><span class=\"mtk12\">org</span><span class=\"mtk1\">.</span><span class=\"mtk12\">pac4j</span><span class=\"mtk1\">.</span><span class=\"mtk12\">core</span><span class=\"mtk1\">.</span><span class=\"mtk12\">config</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Config</span><span class=\"mtk1\">.</span><span class=\"mtk12\">class</span><span class=\"mtk1\">).</span><span class=\"mtk11\">toInstance</span><span class=\"mtk1\">(config);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\">// callback</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">CallbackController</span><span class=\"mtk1\"> </span><span class=\"mtk12\">callbackController</span><span class=\"mtk1\"> = </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> </span><span class=\"mtk11\">CallbackController</span><span class=\"mtk1\">();</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">callbackController</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setDefaultUrl</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">bind</span><span class=\"mtk1\">(</span><span class=\"mtk12\">CallbackController</span><span class=\"mtk1\">.</span><span class=\"mtk12\">class</span><span class=\"mtk1\">).</span><span class=\"mtk11\">toInstance</span><span class=\"mtk1\">(callbackController);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\">// logout</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">LogoutController</span><span class=\"mtk1\"> </span><span class=\"mtk12\">logoutController</span><span class=\"mtk1\"> = </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> </span><span class=\"mtk11\">LogoutController</span><span class=\"mtk1\">();</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">logoutController</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setDefaultUrl</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/?defaulturlafterlogout&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">bind</span><span class=\"mtk1\">(</span><span class=\"mtk12\">LogoutController</span><span class=\"mtk1\">.</span><span class=\"mtk12\">class</span><span class=\"mtk1\">).</span><span class=\"mtk11\">toInstance</span><span class=\"mtk1\">(logoutController);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">private</span><span class=\"mtk1\"> </span><span class=\"mtk10\">void</span><span class=\"mtk1\"> </span><span class=\"mtk11\">addProviderMetadata</span><span class=\"mtk1\">(</span><span class=\"mtk10\">OidcConfiguration</span><span class=\"mtk1\"> </span><span class=\"mtk12\">oidcConfiguration</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">JSONObject</span><span class=\"mtk1\"> </span><span class=\"mtk12\">jsonObj</span><span class=\"mtk1\"> = </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> </span><span class=\"mtk11\">JSONObject</span><span class=\"mtk1\">();</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">jsonObj</span><span class=\"mtk1\">.</span><span class=\"mtk11\">appendField</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;token_endpoint&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">configuration</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getString</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;oidc.tokenUri&quot;</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">OIDCProviderMetadata</span><span class=\"mtk1\"> </span><span class=\"mtk12\">providerMetaData</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">try</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            providerMetaData = </span><span class=\"mtk12\">OIDCProviderMetadata</span><span class=\"mtk1\">.</span><span class=\"mtk11\">parse</span><span class=\"mtk1\">(jsonObj);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk12\">oidcConfiguration</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setProviderMetadata</span><span class=\"mtk1\">(providerMetaData);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        } </span><span class=\"mtk15\">catch</span><span class=\"mtk1\"> (</span><span class=\"mtk10\">ParseException</span><span class=\"mtk1\"> </span><span class=\"mtk12\">e</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk12\">e</span><span class=\"mtk1\">.</span><span class=\"mtk11\">printStackTrace</span><span class=\"mtk1\">();</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<h3 id=\"3-create-secured-endpoint-in-controller\" style=\"position:relative;\"><a href=\"#3-create-secured-endpoint-in-controller\" aria-label=\"3 create secured endpoint in controller permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3. Create Secured Endpoint in Controller</h3>\n<p>In <code>app/controllers/HomeController.java</code> add the following methods</p>\n<ul>\n<li>A method that is secured by the OIDC client</li>\n<li>A method to show the profile information returned from LoginRadius(or any identity provider) on successful login.</li>\n<li>A method to get profile information</li>\n</ul>\n<p>After adding the above methods <code>HomeController.java</code> looks like this.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"java\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">package</span><span class=\"mtk1\"> controllers;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> com.google.inject.Inject;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.core.context.session.SessionStore;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.core.profile.ProfileManager;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.core.profile.UserProfile;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.play.context.PlayContextFactory;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.play.java.Secure;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> org.pac4j.play.store.PlayCacheSessionStore;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> play.mvc.*;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> java.util.ArrayList;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">import</span><span class=\"mtk1\"> java.util.List;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/**</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\"> * This controller contains an action to handle HTTP requests</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\"> * to the application&#39;s home page.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\"> */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">public</span><span class=\"mtk1\"> </span><span class=\"mtk4\">class</span><span class=\"mtk1\"> </span><span class=\"mtk10\">HomeController</span><span class=\"mtk1\"> </span><span class=\"mtk4\">extends</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Controller</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">    /**</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">     * An action that renders an HTML page with a welcome message.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">     * The configuration in the &lt;code&gt;routes&lt;/code&gt; file means that</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">     * this method will be called when the application receives a</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">     * &lt;code&gt;GET&lt;/code&gt; request with a path of &lt;code&gt;/&lt;/code&gt;.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">     */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Result</span><span class=\"mtk1\"> </span><span class=\"mtk11\">index</span><span class=\"mtk1\">() {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk11\">ok</span><span class=\"mtk1\">(</span><span class=\"mtk12\">views</span><span class=\"mtk1\">.</span><span class=\"mtk12\">html</span><span class=\"mtk1\">.</span><span class=\"mtk12\">index</span><span class=\"mtk1\">.</span><span class=\"mtk11\">render</span><span class=\"mtk1\">());</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    @</span><span class=\"mtk10\">Secure</span><span class=\"mtk1\">(clients = </span><span class=\"mtk8\">&quot;OidcClient&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Result</span><span class=\"mtk1\"> </span><span class=\"mtk11\">oidcIndex</span><span class=\"mtk1\">(</span><span class=\"mtk10\">Http</span><span class=\"mtk1\">.</span><span class=\"mtk10\">Request</span><span class=\"mtk1\"> </span><span class=\"mtk12\">req</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk11\">protectedIndex</span><span class=\"mtk1\">(req);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Result</span><span class=\"mtk1\"> </span><span class=\"mtk11\">protectedIndex</span><span class=\"mtk1\">(</span><span class=\"mtk10\">Http</span><span class=\"mtk1\">.</span><span class=\"mtk10\">Request</span><span class=\"mtk1\"> </span><span class=\"mtk12\">req</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk11\">ok</span><span class=\"mtk1\">(</span><span class=\"mtk12\">views</span><span class=\"mtk1\">.</span><span class=\"mtk12\">html</span><span class=\"mtk1\">.</span><span class=\"mtk12\">protectedindex</span><span class=\"mtk1\">.</span><span class=\"mtk11\">render</span><span class=\"mtk1\">(</span><span class=\"mtk11\">getProfiles</span><span class=\"mtk1\">(req)));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    @</span><span class=\"mtk10\">Inject</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">private</span><span class=\"mtk1\"> </span><span class=\"mtk10\">SessionStore</span><span class=\"mtk1\"> </span><span class=\"mtk12\">sessionStore</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">private</span><span class=\"mtk1\"> </span><span class=\"mtk10\">List</span><span class=\"mtk1\">&lt;</span><span class=\"mtk10\">UserProfile</span><span class=\"mtk1\">&gt; </span><span class=\"mtk11\">getProfiles</span><span class=\"mtk1\">(</span><span class=\"mtk10\">Http</span><span class=\"mtk1\">.</span><span class=\"mtk10\">Request</span><span class=\"mtk1\"> </span><span class=\"mtk12\">req</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">ProfileManager</span><span class=\"mtk1\"> </span><span class=\"mtk12\">profileManager</span><span class=\"mtk1\"> = </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> </span><span class=\"mtk11\">ProfileManager</span><span class=\"mtk1\">(</span><span class=\"mtk12\">PlayContextFactory</span><span class=\"mtk1\">.</span><span class=\"mtk12\">INSTANCE</span><span class=\"mtk1\">.</span><span class=\"mtk11\">newContext</span><span class=\"mtk1\">(req), sessionStore);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">List</span><span class=\"mtk1\">&lt;</span><span class=\"mtk10\">UserProfile</span><span class=\"mtk1\">&gt; </span><span class=\"mtk12\">profiles</span><span class=\"mtk1\"> = </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> </span><span class=\"mtk10\">ArrayList</span><span class=\"mtk1\">&lt;&gt;();</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">profileManager</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getProfile</span><span class=\"mtk1\">().</span><span class=\"mtk11\">isPresent</span><span class=\"mtk1\">()) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk12\">profiles</span><span class=\"mtk1\">.</span><span class=\"mtk11\">add</span><span class=\"mtk1\">(</span><span class=\"mtk12\">profileManager</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getProfile</span><span class=\"mtk1\">().</span><span class=\"mtk11\">get</span><span class=\"mtk1\">());</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> profiles;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<h3 id=\"4-create-views\" style=\"position:relative;\"><a href=\"#4-create-views\" aria-label=\"4 create views permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4. Create Views</h3>\n<ul>\n<li>Update <code>app/views/index.scala.html</code> as follows to add the link protected by OIDC authentication.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">@()</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">@</span><span class=\"mtk11\">main</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Welcome to Play&quot;</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">h1</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">Welcome to Play!</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">h1</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">a</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;oidc/index.html&quot;</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">Protected URL by OIDC</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">a</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<ul>\n<li>Add <code>app/views/protectedindex.scala.html</code> with the following content below. This page will be shown after Successful Login using OIDC in LoginRadius.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">@(</span><span class=\"mtk12\">profileList</span><span class=\"mtk1\">: </span><span class=\"mtk10\">java</span><span class=\"mtk1\">.</span><span class=\"mtk10\">util</span><span class=\"mtk1\">.</span><span class=\"mtk10\">List</span><span class=\"mtk1\">[</span><span class=\"mtk10\">org</span><span class=\"mtk1\">.</span><span class=\"mtk10\">pac4j</span><span class=\"mtk1\">.</span><span class=\"mtk10\">core</span><span class=\"mtk1\">.</span><span class=\"mtk10\">profile</span><span class=\"mtk1\">.</span><span class=\"mtk10\">UserProfile</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">@import scala.collection.JavaConverters._</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">@profiles() = { @profileList.</span><span class=\"mtk12\">toList</span><span class=\"mtk1\"> }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">h1</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">Protected Area</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">h1</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">a</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;..&quot;</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">Back</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">a</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">ul</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">li</span><span class=\"mtk17\">&gt;&lt;</span><span class=\"mtk4\">a</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;/logout?url=/?forcepostlogouturl&quot;</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">Logout</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">a</span><span class=\"mtk17\">&gt;&lt;/</span><span class=\"mtk4\">li</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">ul</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">p</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    profiles: @profiles</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">p</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<h3 id=\"5-configure-routes\" style=\"position:relative;\"><a href=\"#5-configure-routes\" aria-label=\"5 configure routes permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5. Configure Routes</h3>\n<p>Now we already added methods in <code>HomeController.java</code> and configured callback, logout controllers in <code>SecurityModule.java</code>. Let's configure the routes to map to these methods in <code>conf/routes</code>.</p>\n<ul>\n<li><code>conf/routes</code> will look like this.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"9\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"># Routes</span>\n<span class=\"grvsc-line\"># This file defines all application routes (Higher priority routes first)</span>\n<span class=\"grvsc-line\"># ~~~~</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"># An example controller showing a sample home page</span>\n<span class=\"grvsc-line\">GET     /                           controllers.HomeController.index</span>\n<span class=\"grvsc-line\">GET     /oidc/index.html            controllers.HomeController.oidcIndex(request: Request)</span>\n<span class=\"grvsc-line\">GET     /protected/index.html       controllers.HomeController.protectedIndex(request: Request)</span>\n<span class=\"grvsc-line\">GET     /callback                   @org.pac4j.play.CallbackController.callback(request: Request)</span>\n<span class=\"grvsc-line\">POST    /callback                   @org.pac4j.play.CallbackController.callback(request: Request)</span>\n<span class=\"grvsc-line\">GET     /logout                     @org.pac4j.play.LogoutController.logout(request: Request)</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"># Map static resources from the /public folder to the /assets URL path</span>\n<span class=\"grvsc-line\">GET     /assets/*file               controllers.Assets.versioned(path=&quot;/public&quot;, file: Asset)</span></code></pre>\n<h3 id=\"6-add-application-configuration-variables\" style=\"position:relative;\"><a href=\"#6-add-application-configuration-variables\" aria-label=\"6 add application configuration variables permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6. Add Application Configuration variables</h3>\n<p>Finally, configure the variables mentioned in <code>SecurityModule.java</code> in <code>conf/application.conf</code> as follows.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"10\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">play {</span>\n<span class=\"grvsc-line\">  modules {</span>\n<span class=\"grvsc-line\">    enabled += modules.SecurityModule</span>\n<span class=\"grvsc-line\">  }</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">baseUrl = &quot;http://localhost:9000&quot;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">oidc.discoveryUri = &quot;https://cloud-api.loginradius.com/sso/oidc/v2/{loginradius-site-name}/{loginradius-app-name}/.well-known/openid-configuration&quot;</span>\n<span class=\"grvsc-line\">oidc.clientId = &quot;{clientId}&quot;</span>\n<span class=\"grvsc-line\">oidc.clientSecret = &quot;{clientSecret}&quot;</span>\n<span class=\"grvsc-line\">oidc.tokenUri = &quot;https://cloud-api.loginradius.com/sso/oidc/v2/{loginradius-site-name}/token&quot;</span></code></pre>\n<h2 id=\"create-an-oidc-app-in-loginradius\" style=\"position:relative;\"><a href=\"#create-an-oidc-app-in-loginradius\" aria-label=\"create an oidc app in loginradius permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Create an OIDC app in LoginRadius</h2>\n<p>Login to your LoginRadius account or <a href=\"https://www.loginradius.com/\">signup here</a> if you don't have one. </p>\n<p>Once you log in you can see by default, one application will be created for you. Otherwise, you can create a new application here from the following screen by clicking <code>New App</code>.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 65.6923076923077%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABYlAAAWJQFJUiTwAAABR0lEQVQ4y61S2U7DMBDM/z+TNgJRrlQ9QQheeCj8DagFEXLbju0Mu27aRIiqQcLSyLs+ZmcP7272guXkGYvxivYVwut7TMcPhEdcnM8RDEL4wykGhMAPMfRvHPxghpNgjtOzBS5HS1yNFridPMGLdA1pDf5reXGS4fVtjfX6HUUpIKSEELQL2dgSUiporXvAwCvpMztSKVRV5aBU1doEvudV1/VReKzgt8WXaGCtdXBnR4i9ktKsO5+sJZt8TjtOEkJKdok8Lyh12QY7VEMmbKPu1AGSCDcfn9hEMQz527qKfgr3LFvDXbCaPM+RZjkKaoooS9ec3go5zUyZ/WNWk6QpFHWOgxljHP5EKHVbeFYYRV9ulHYkXOPehOg8qhtFP7vbtXs2pQXPYkF1q/Q2TQ7QnceDhLvOtWNj9woVDbs2pvFtr5S/AXDE7uVD3HNaAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"loginradius-dashboard.png\"\n        title=\"loginradius-dashboard.png\"\n        src=\"/static/19ce2c82b61d0cbc22b842b0b1158fb8/e5715/loginradius-dashboard.png\"\n        srcset=\"/static/19ce2c82b61d0cbc22b842b0b1158fb8/a6d36/loginradius-dashboard.png 650w,\n/static/19ce2c82b61d0cbc22b842b0b1158fb8/e5715/loginradius-dashboard.png 768w,\n/static/19ce2c82b61d0cbc22b842b0b1158fb8/78302/loginradius-dashboard.png 2798w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>I will be using the existing application itself for this demo as I am using a free plan. In the free plan, you can create only one application (no need for card details).</p>\n<p>Upgrade your application subscription to the <code>Developer Pro</code> Plan to configure OIDC. (<code>Developer Pro</code> Plan is available with 21 days trial).</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 77.6923076923077%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAABxUlEQVQ4y41TWS8DURid/8cDsSRVRVCCSFpLI0UiEQ0SiQdC4okQ3iTibxAPlsT6JNZROtPZ7twe95vNVKfLl5y5y9x7vvMtVxpI5DDYvYyBrhySYkwmVhDrmEAilkJ/T8ZBb3wSna2jaGlKoqV5qCakJ7mI53wRPwUFZLLOYDAOlErgNgfnhBIaNUlVVRDy399QxCiYBFd1kAPbtmHzaEiKoqIg1L2+vePjU4am6y40H5oHd25ZVk2HkqsKTliBdwFGYLYXsgu6ELaahP5G6LjzJUWGYcAwTei6q1ItFmGKtX+vLIcUsp+bMEgl2frmFobH00hNZzGVncfswiImZ+awd3DkRcbLFRYUpaJSYbW51TW0x/swksrg4fEJX195ketPXF7fREYWEAY/Qt7IFpaW0dwWQ3IsjZfXt0D57d19fcKQxGB9fHKKje0d7O4f4uz8wlFGuKqnkMwWlZY1Bu4doPwYhgk6Y1g2LEaVZ86eKYpVl5CIdPFKwoS6qLAizpimFbQWkTIv9MZC9lom6ElB4M9JGXWG1YjCPypUEv5rbFpHEvp9GAUio4amkDWRN+7tW8IBpSCaMHh6vCqYo7RyP4rwF+S4sMVgf10uAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"loginradius-upgrade-subscription-1.png\"\n        title=\"loginradius-upgrade-subscription-1.png\"\n        src=\"/static/5c1a296411b3ae0135c3faddf34ac8a2/e5715/loginradius-upgrade-subscription-1.png\"\n        srcset=\"/static/5c1a296411b3ae0135c3faddf34ac8a2/a6d36/loginradius-upgrade-subscription-1.png 650w,\n/static/5c1a296411b3ae0135c3faddf34ac8a2/e5715/loginradius-upgrade-subscription-1.png 768w,\n/static/5c1a296411b3ae0135c3faddf34ac8a2/037ab/loginradius-upgrade-subscription-1.png 2274w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 69.6923076923077%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB+0lEQVQ4y42TzW8SQRiH+d8aNZrGphSs8WLSkxdj+eqys98CBT+uhpiiRxL16AWUiz1bOJF4EE1Mq12uWsTdhZ/vO8suUmgsyZN3Zph9+M3OSyK1uYtbmw+Qvnkft5MZbG3cw/qNO0hv7SCV3EFy4y6uX9vGlbUUrq6l/0tCMTQouoBpaXDKNqyHNvb3y6hUSjHVagXVWmVez8Pr1bIkUVSKUIhsNi+roRvQNI3QY4QQUFUh14XQ5DysIbquE4YkUSyqMIxIEop4QyijOY0dx0GpxGk5SQ212iNiXm3bhmmahBUKLcu6EP6xD4eH+HZ8gs+DLzg++Q53OMSp68J1h/hx6qJer8vUvF8KQ/synDRfKKDf7+Oiz8gLcNBoQKiqTLqU0IwqC+nI2VweH4+OMJ1O4fs+JpPJAp7noUFC9byQBQvimbBACbvdXvwwi/8VBkGwLIxSGSwxzFjIl6IoCrq9HgJ6+A8JfRJwUhbx2tjzVwhn6YRuSkIhzUmYy+XQIyFLfp2dYTQaScbjMb3BCTG9/JEZ3jgYDFZeyKefwOuvv3Hw4uWKSzHnkkhozG662Wyi0+mg1Wqh3W6jRXTev8OzV2+x+/wNHj95Su2lX65tuL+4dfjoTCaTicdirwBH3ZP7ohALR14FNzZ/z/8WPhLDYzknLNtZeGV/AY5b/JlWBK13AAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"loginradius-upgrade-subscription-2.png\"\n        title=\"loginradius-upgrade-subscription-2.png\"\n        src=\"/static/6b180247c629f7ccad7e90c2f9568ef5/e5715/loginradius-upgrade-subscription-2.png\"\n        srcset=\"/static/6b180247c629f7ccad7e90c2f9568ef5/a6d36/loginradius-upgrade-subscription-2.png 650w,\n/static/6b180247c629f7ccad7e90c2f9568ef5/e5715/loginradius-upgrade-subscription-2.png 768w,\n/static/6b180247c629f7ccad7e90c2f9568ef5/52a2d/loginradius-upgrade-subscription-2.png 2534w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>Now click on <code>Select &#x26; Configure</code> on your application and navigate to the <code>Integration</code> Section and Configure <code>Open ID</code> configuration. You can find step-by-step details to <a href=\"https://www.loginradius.com/developers/\">configure OIDC</a> here.</p>\n<p>Once you configure these <code>conf/application.conf</code> will look something like this.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"11\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"># This is the main configuration file for the application.</span>\n<span class=\"grvsc-line\"># https://www.playframework.com/documentation/latest/ConfigFile</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">play {</span>\n<span class=\"grvsc-line\">  modules {</span>\n<span class=\"grvsc-line\">    enabled += modules.SecurityModule</span>\n<span class=\"grvsc-line\">  }</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">baseUrl = &quot;http://localhost:9000&quot;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">oidc.discoveryUri = &quot;https://cloud-api.loginradius.com/sso/oidc/v2/dev-svv3qlcj2y/pac4j-play-loginradius-demo/.well-known/openid-configuration&quot;</span>\n<span class=\"grvsc-line\">oidc.clientId = &quot;8ce24413-9b7e-4282-9f5b-e0e5ec13a42a&quot;</span>\n<span class=\"grvsc-line\">oidc.clientSecret = &quot;c9c61f6e-325f-40d6-89fd-696d17f970eb&quot;</span>\n<span class=\"grvsc-line\">oidc.tokenUri = &quot;https://cloud-api.loginradius.com/sso/oidc/v2/dev-svv3qlcj2y/token&quot;</span>\n<span class=\"grvsc-line\"># Site Name - dev-svv3qlcj2y</span>\n<span class=\"grvsc-line\"># App Name - pac4j-play-loginradius-demo</span></code></pre>\n<h2 id=\"time-to-test-complete-integration\" style=\"position:relative;\"><a href=\"#time-to-test-complete-integration\" aria-label=\"time to test complete integration permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Time to test complete Integration</h2>\n<p>Let's run our application using <code>sbt clean run</code> and visit <code>http://localhost:9000</code>. The Home page will look like this.</p>\n<h3 id=\"home-page\" style=\"position:relative;\"><a href=\"#home-page\" aria-label=\"home page permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Home Page</h3>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 27.692307692307693%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAbUlEQVQY062OwQqAIBBE9/8/0OoUdRbRrURDncxTWERCAw922WF5JKWE1hpKKRhjYJixrGuZnfOIMSKEkIkv5PvZ2xjUdwOmcYYQojytk1L6Tu6T5R2WPcr28KApuU+1SbNVBd2MEtrNLiH8nAPPEtpLdJBSVwAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"home-page.png\"\n        title=\"home-page.png\"\n        src=\"/static/a6ab822950175d12e45d43fb76ca2967/e5715/home-page.png\"\n        srcset=\"/static/a6ab822950175d12e45d43fb76ca2967/a6d36/home-page.png 650w,\n/static/a6ab822950175d12e45d43fb76ca2967/e5715/home-page.png 768w,\n/static/a6ab822950175d12e45d43fb76ca2967/cbe7f/home-page.png 2420w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h3 id=\"loginradius-auth-page-idx\" style=\"position:relative;\"><a href=\"#loginradius-auth-page-idx\" aria-label=\"loginradius auth page idx permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>LoginRadius Auth Page (IDX)</h3>\n<p>Now click on the <code>protected url by OIDC</code> link on the home page that will redirect you to the LoginRadius Auth Page (IDX), which you configured.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 61.07692307692307%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAACXElEQVQoz3WTS2sTURiGTyZp00xm0twvzT12YhNTklJrIdWFBcG0tQ2Iim5EV/4CEaRidaNQxdpYRS2oUFsEXYvtxp0L9+5FdC8o2pY8nkmaNqG4ePnOZXjO+57vjKhUJqhWq5yanGB8fJyxcpmZyQqXzk5TvbXG6FsYW/1Nee0v5dU/jTpmjqWOyflRc/5mm5HVTUZXfiH8/gDRaAy/z4ewWLFZFdKZDIV0BP3MXcQSiPltxH3+r3tt41A4gsXahcOpo2k6Q0NFSsMjJHwq2sxNLMtgXdhEWayj1OqNKh52ytK+ZxhZNN0lgS7cmkoyHsUXDOHpFhI4h3guT32whWiAJLwGh1aaKkilXoBNrpl7YlEql8uTDAexKDZ6dR2fy0kkFifh1/Cek5GfyY8WWkDTCRiv6mSl0i9Bf2I6bAMOHz7CUKlEKpXkQCpByKMRlA5TAQ11anafQzNaSK55nkLPUh31sVnbgANGP/FohICnl7DbyaCRJhTw4xAC+8lriGUTuLkLNCGvv2zx8Vudja/w6UedO5/NFDvAWMiHX+/BZVfQe2xk+oIU+1NkPQq+03P7ItsewYUPcHkDzr+vc3Edjr9rc1gsFkj2hXGrXbgcXSQScYysQS7owDl9Yy+y2dHF5thyZR1x+zvCbMZ8vflcWvdYyB3EiIUbLt0OG1EJTOULqDKytTK7F7kFNJ/J/E8U8ynVmnfa0ZRSfoCIW8Wr2fFIl25dJZ/PE7YLLCeudgJb0Bq7cNEOMzUoHfolLKB3E+p1EPG6yMg/xfAqOKeu70TudNgBb9Ud/QNovwJ4rzBaFgAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"loginradius-consent-page.png\"\n        title=\"loginradius-consent-page.png\"\n        src=\"/static/2c30cb2b6ecd675ee7f6adecae33022c/e5715/loginradius-consent-page.png\"\n        srcset=\"/static/2c30cb2b6ecd675ee7f6adecae33022c/a6d36/loginradius-consent-page.png 650w,\n/static/2c30cb2b6ecd675ee7f6adecae33022c/e5715/loginradius-consent-page.png 768w,\n/static/2c30cb2b6ecd675ee7f6adecae33022c/0bd07/loginradius-consent-page.png 2898w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h3 id=\"redirect-to-protected-index-page\" style=\"position:relative;\"><a href=\"#redirect-to-protected-index-page\" aria-label=\"redirect to protected index page permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Redirect to Protected Index Page</h3>\n<p>On successful login from the above step, you will be redirected to the <code>protectedindex.scala.html</code> page.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 27.53846153846154%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAAArklEQVQY062QfQuDIBDG/f5fr3ctwhq0P4KVrazcfKYHQg3GGEz48Tzn6Z0eq+saXXfFPE1Y1Ih5HEh3vcDuG57bkRUPp+ausLlzel3RqxnDrcekFEZ3j+lFwxiDfy0muIAQAlmWEUVRgHOOPM/JH5FS4tK2pE3TEFIGlWhdjkVRhDiOkSQJEbwv7jVN09N+WZbUsKoq+HH5OOCLMmvt6cnH2Pv3/Ncv/zqj0OQTL9GMyioWc8KWAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"loginradius-protected-index-page.png\"\n        title=\"loginradius-protected-index-page.png\"\n        src=\"/static/d83ff98f9f5a31ea8e23d98a8cc079e4/e5715/loginradius-protected-index-page.png\"\n        srcset=\"/static/d83ff98f9f5a31ea8e23d98a8cc079e4/a6d36/loginradius-protected-index-page.png 650w,\n/static/d83ff98f9f5a31ea8e23d98a8cc079e4/e5715/loginradius-protected-index-page.png 768w,\n/static/d83ff98f9f5a31ea8e23d98a8cc079e4/8c565/loginradius-protected-index-page.png 3346w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h3 id=\"logout-action\" style=\"position:relative;\"><a href=\"#logout-action\" aria-label=\"logout action permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Logout Action</h3>\n<p><a href=\"https://github.com/pac4j/play-pac4j\">play-pac4j</a> provides out of the box <code>LogoutController</code> which can be used to handle logout flows. It has <code>logout</code> functionality which has the logout logic implementation to clear the session. Below is the sample <code>logout</code> functionality from <code>org.pac4j.play.LogoutController</code> play-pac4j module.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"java\" data-index=\"12\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> </span><span class=\"mtk10\">CompletionStage</span><span class=\"mtk1\">&lt;Result&gt; </span><span class=\"mtk11\">logout</span><span class=\"mtk1\">(</span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk12\">Http</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Request</span><span class=\"mtk1\"> request) {</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">HttpActionAdapter</span><span class=\"mtk1\"> </span><span class=\"mtk12\">bestAdapter</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">FindBest</span><span class=\"mtk1\">.</span><span class=\"mtk11\">httpActionAdapter</span><span class=\"mtk1\">(</span><span class=\"mtk4\">null</span><span class=\"mtk1\">, config, </span><span class=\"mtk12\">PlayHttpActionAdapter</span><span class=\"mtk1\">.</span><span class=\"mtk12\">INSTANCE</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">LogoutLogic</span><span class=\"mtk1\"> </span><span class=\"mtk12\">bestLogic</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">FindBest</span><span class=\"mtk1\">.</span><span class=\"mtk11\">logoutLogic</span><span class=\"mtk1\">(logoutLogic, config, </span><span class=\"mtk12\">DefaultLogoutLogic</span><span class=\"mtk1\">.</span><span class=\"mtk12\">INSTANCE</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">WebContext</span><span class=\"mtk1\"> </span><span class=\"mtk12\">context</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">FindBest</span><span class=\"mtk1\">.</span><span class=\"mtk11\">webContextFactory</span><span class=\"mtk1\">(</span><span class=\"mtk4\">null</span><span class=\"mtk1\">, config, </span><span class=\"mtk12\">PlayContextFactory</span><span class=\"mtk1\">.</span><span class=\"mtk12\">INSTANCE</span><span class=\"mtk1\">).</span><span class=\"mtk11\">newContext</span><span class=\"mtk1\">(request);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">CompletableFuture</span><span class=\"mtk1\">.</span><span class=\"mtk11\">supplyAsync</span><span class=\"mtk1\">(() </span><span class=\"mtk4\">-&gt;</span><span class=\"mtk1\"> (Result) </span><span class=\"mtk12\">bestLogic</span><span class=\"mtk1\">.</span><span class=\"mtk11\">perform</span><span class=\"mtk1\">(context, sessionStore, config, bestAdapter, </span><span class=\"mtk4\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">defaultUrl</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk4\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">logoutUrlPattern</span><span class=\"mtk1\">, </span><span class=\"mtk4\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">localLogout</span><span class=\"mtk1\">, </span><span class=\"mtk4\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">destroySession</span><span class=\"mtk1\">, </span><span class=\"mtk4\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">centralLogout</span><span class=\"mtk1\">), </span><span class=\"mtk12\">ec</span><span class=\"mtk1\">.</span><span class=\"mtk11\">current</span><span class=\"mtk1\">());</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>So to use this LogoutController, we just need to initialize it and define logout route for the same in our <code>routes</code>. We already initialized LoginController in <code>SecurityModule.java</code>.</p>\n<h4 id=\"a-initialize-logoutcontroller\" style=\"position:relative;\"><a href=\"#a-initialize-logoutcontroller\" aria-label=\"a initialize logoutcontroller permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>a. Initialize LogoutController</h4>\n<ul>\n<li>You can configure default url which application needs to redirect after <code>logout</code> action.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"java\" data-index=\"13\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">// logout</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">final</span><span class=\"mtk1\"> </span><span class=\"mtk10\">LogoutController</span><span class=\"mtk1\"> </span><span class=\"mtk12\">logoutController</span><span class=\"mtk1\"> = </span><span class=\"mtk15\">new</span><span class=\"mtk1\"> </span><span class=\"mtk11\">LogoutController</span><span class=\"mtk1\">();</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">logoutController</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setDefaultUrl</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/?defaulturlafterlogout&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">bind</span><span class=\"mtk1\">(</span><span class=\"mtk12\">LogoutController</span><span class=\"mtk1\">.</span><span class=\"mtk12\">class</span><span class=\"mtk1\">).</span><span class=\"mtk11\">toInstance</span><span class=\"mtk1\">(logoutController);</span></span></code></pre>\n<h4 id=\"b-define-route-for-logoutcontroller\" style=\"position:relative;\"><a href=\"#b-define-route-for-logoutcontroller\" aria-label=\"b define route for logoutcontroller permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>b. Define Route for LogoutController</h4>\n<ul>\n<li>We already configured <code>/logout</code> Route using <code>LogoutController</code> in <code>conf/routes</code>.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"14\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">GET     /logout                     @org.pac4j.play.LogoutController.logout(request: Request)</span></code></pre>\n<p>On Clicking <code>logout</code> in our application, the session will be cleared and you will be redirected to the Home page based on our configuration. </p>\n<h2 id=\"source-code\" style=\"position:relative;\"><a href=\"#source-code\" aria-label=\"source code permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Source Code</h2>\n<p>You can see the full source code for the application developed in this tutorial on <a href=\"https://github.com/vishnuchilamakuru/loginradius-play-oidc-example\">GitHub</a>.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n  .dark-default-dark .mtk17 { color: #808080; }\n</style>","frontmatter":{"date":"June 25, 2021","updated_date":null,"title":"Add Authentication to Play Framework With OIDC and LoginRadius","tags":["OIDC","Java","pac4j","Play Framework","Authentication"],"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/7fda86ee912dfb6374d4838c3062813c/ee604/pac4j-authentication.png","srcSet":"/static/7fda86ee912dfb6374d4838c3062813c/69585/pac4j-authentication.png 200w,\n/static/7fda86ee912dfb6374d4838c3062813c/497c6/pac4j-authentication.png 400w,\n/static/7fda86ee912dfb6374d4838c3062813c/ee604/pac4j-authentication.png 800w,\n/static/7fda86ee912dfb6374d4838c3062813c/db955/pac4j-authentication.png 900w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Vishnu Chilamakuru","github":"vishnuchilamakuru","avatar":null}}}},{"node":{"fields":{"slug":"/engineering/pkce/"},"html":"<p>PKCE is an OAuth 2.0 security extension for public clients on mobile devices intended to avoid a malicious programme creeping into the same computer from intercepting the authorisation code. The <a href=\"https://oauth.net/2/pkce/\">RFC 7636</a> introduction discusses the mechanisms of such an attack.</p>\n<p>PKCE has a different specification of its own. It allows applications to use the most reliable OAuth 2.0 flows in public or untrusted clients - the Authorization Code flow. In order to efficiently use a dynamically generated password, it achieves this by doing some setup work before the flow and some verification at the end of the flow. </p>\n<p>This is important because getting a fixed secret in a public client is not safe.</p>\n<p>In this blog, we will see how PKCE is useful in authorization code flow for OAuth and OIDC and how you can use this with your OAuth and OpenID Connect providers.</p>\n<h2 id=\"what-is-pkce\" style=\"position:relative;\"><a href=\"#what-is-pkce\" aria-label=\"what is pkce permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is PKCE</h2>\n<p>Proof Key for Code Exchange as known as PKCE, is a key for preventing malicious attacks and securely performing code authorization flow.</p>\n<p>I would say, PKCE is used to provide one more security layer to the authorization code flow in <a href=\"/oauth2/\">OAuth</a> and OpenID Connect.</p>\n<p>PKCE is mainly useful for the client-side application or any web apps that are using the client secret key and used to replace the static secret used in the authorization flow.</p>\n<p>This flow basically works with two parameters <strong>Code Verifier</strong> and <strong>Code challenge</strong>. Let's see what are these parameters, how we use them, and generate them.</p>\n<h3 id=\"pkce-code-verifier-and-challenge\" style=\"position:relative;\"><a href=\"#pkce-code-verifier-and-challenge\" aria-label=\"pkce code verifier and challenge permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>PKCE code verifier and challenge</h3>\n<p><strong>The code verifier</strong> is a cryptographically random string using the characters A-Z, a-z, 0-9, and the punctuation characters -._~ (hyphen, period, underscore, and tilde), between 43 and 128 characters long.\nOnce the client has generated the code verifier, it uses that to create the <strong>code challenge</strong>.</p>\n<p>For devices that can perform a SHA256 hash, the code challenge is a BASE64-URL-encoded string of the SHA256 hash of the code verifier.</p>\n<h3 id=\"generate-code-verifier-and-code-challenge\" style=\"position:relative;\"><a href=\"#generate-code-verifier-and-code-challenge\" aria-label=\"generate code verifier and code challenge permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Generate code verifier and code challenge</h3>\n<p>Here you can see the examples to generate the Code verifier and code challenge in different languages. Either you <a href=\"/oAuth-implemenation-using-node/\">can find Node</a> and <a href=\"/golang-maps/\">Go Packages</a> for this but I would recommend you to not depend on any package for such small things.</p>\n<p><strong>NodeJs</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">crypto</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;crypto&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">base64URLEncode</span><span class=\"mtk1\">(</span><span class=\"mtk12\">str</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">str</span><span class=\"mtk1\">.</span><span class=\"mtk11\">toString</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;base64&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        .</span><span class=\"mtk11\">replace</span><span class=\"mtk1\">(</span><span class=\"mtk5\">/</span><span class=\"mtk6\">\\+</span><span class=\"mtk5\">/</span><span class=\"mtk4\">g</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&#39;-&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        .</span><span class=\"mtk11\">replace</span><span class=\"mtk1\">(</span><span class=\"mtk5\">/</span><span class=\"mtk6\">\\/</span><span class=\"mtk5\">/</span><span class=\"mtk4\">g</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&#39;_&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        .</span><span class=\"mtk11\">replace</span><span class=\"mtk1\">(</span><span class=\"mtk5\">/=/</span><span class=\"mtk4\">g</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&#39;&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">verifier</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">base64URLEncode</span><span class=\"mtk1\">(</span><span class=\"mtk12\">crypto</span><span class=\"mtk1\">.</span><span class=\"mtk11\">randomBytes</span><span class=\"mtk1\">(</span><span class=\"mtk7\">32</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;code_verifier: &quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">verifier</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">if</span><span class=\"mtk1\">(</span><span class=\"mtk12\">verifier</span><span class=\"mtk1\">){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">challenge</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">base64URLEncode</span><span class=\"mtk1\">(</span><span class=\"mtk11\">sha256</span><span class=\"mtk1\">(</span><span class=\"mtk12\">verifier</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;code_challenge: &quot;</span><span class=\"mtk1\">,</span><span class=\"mtk12\">challenge</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">sha256</span><span class=\"mtk1\">(</span><span class=\"mtk12\">buffer</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">crypto</span><span class=\"mtk1\">.</span><span class=\"mtk11\">createHash</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;sha256&#39;</span><span class=\"mtk1\">).</span><span class=\"mtk11\">update</span><span class=\"mtk1\">(</span><span class=\"mtk12\">buffer</span><span class=\"mtk1\">).</span><span class=\"mtk11\">digest</span><span class=\"mtk1\">();</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p><strong>Golang</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"golang\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">package main</span>\n<span class=\"grvsc-line\"> </span>\n<span class=\"grvsc-line\">import (</span>\n<span class=\"grvsc-line\">    &quot;crypto/sha256&quot;</span>\n<span class=\"grvsc-line\">    &quot;encoding/base64&quot;</span>\n<span class=\"grvsc-line\">    &quot;fmt&quot;</span>\n<span class=\"grvsc-line\">    &quot;math/rand&quot;</span>\n<span class=\"grvsc-line\">    &quot;strings&quot;</span>\n<span class=\"grvsc-line\">    &quot;time&quot;</span>\n<span class=\"grvsc-line\">)</span>\n<span class=\"grvsc-line\"> </span>\n<span class=\"grvsc-line\">type CodeVerifier struct {</span>\n<span class=\"grvsc-line\">    Value string</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"> </span>\n<span class=\"grvsc-line\">const (</span>\n<span class=\"grvsc-line\">    length = 32</span>\n<span class=\"grvsc-line\">)</span>\n<span class=\"grvsc-line\"> </span>\n<span class=\"grvsc-line\">func base64URLEncode(str []byte) string {</span>\n<span class=\"grvsc-line\">    encoded := base64.StdEncoding.EncodeToString(str)</span>\n<span class=\"grvsc-line\">    encoded = strings.Replace(encoded, &quot;+&quot;, &quot;-&quot;, -1)</span>\n<span class=\"grvsc-line\">    encoded = strings.Replace(encoded, &quot;/&quot;, &quot;_&quot;, -1)</span>\n<span class=\"grvsc-line\">    encoded = strings.Replace(encoded, &quot;=&quot;, &quot;&quot;, -1)</span>\n<span class=\"grvsc-line\">    return encoded</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"> </span>\n<span class=\"grvsc-line\">func verifier() (*CodeVerifier, error) {</span>\n<span class=\"grvsc-line\">    r := rand.New(rand.NewSource(time.Now().UnixNano()))</span>\n<span class=\"grvsc-line\">    b := make([]byte, length, length)</span>\n<span class=\"grvsc-line\">    for i := 0; i &lt; length; i++ {</span>\n<span class=\"grvsc-line\">        b[i] = byte(r.Intn(255))</span>\n<span class=\"grvsc-line\">    }</span>\n<span class=\"grvsc-line\">    return CreateCodeVerifierFromBytes(b)</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"> </span>\n<span class=\"grvsc-line\">func CreateCodeVerifierFromBytes(b []byte) (*CodeVerifier, error) {</span>\n<span class=\"grvsc-line\">    return &CodeVerifier{</span>\n<span class=\"grvsc-line\">        Value: base64URLEncode(b),</span>\n<span class=\"grvsc-line\">    }, nil</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"> </span>\n<span class=\"grvsc-line\">func (v *CodeVerifier) CodeChallengeS256() string {</span>\n<span class=\"grvsc-line\">    h := sha256.New()</span>\n<span class=\"grvsc-line\">    h.Write([]byte(v.Value))</span>\n<span class=\"grvsc-line\">    return base64URLEncode(h.Sum(nil))</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"> </span>\n<span class=\"grvsc-line\">func main() {</span>\n<span class=\"grvsc-line\">    verifier, _ := verifier()</span>\n<span class=\"grvsc-line\">    fmt.Println(&quot;code_verifier: &quot;, verifier.Value)</span>\n<span class=\"grvsc-line\">    challenge := verifier.CodeChallengeS256()</span>\n<span class=\"grvsc-line\">    fmt.Println(&quot;code_challenge :&quot;, challenge)</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"> </span></code></pre>\n<h2 id=\"implement-the-oauth-20-authorization-code-with-pkce-flow\" style=\"position:relative;\"><a href=\"#implement-the-oauth-20-authorization-code-with-pkce-flow\" aria-label=\"implement the oauth 20 authorization code with pkce flow permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Implement the OAuth 2.0 Authorization Code with PKCE Flow</h2>\n<h3 id=\"get-the-authorization-code\" style=\"position:relative;\"><a href=\"#get-the-authorization-code\" aria-label=\"get the authorization code permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Get the Authorization code</h3>\n<p>In the OAuth Authorization flow, we need to have the code verifier and code challenge to start with the authentication and obviously an OAuth provider to connect.</p>\n<p> For the initial request, we need to pass the code<em>challenge and code</em>challenge_method to the OAuth or OIDC provider that supports PKCE based flow.</p>\n<p>The request will look like: </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">Provider + /oauth/redirect?</span>\n<span class=\"grvsc-line\">client_id={client_id}</span>\n<span class=\"grvsc-line\">&redirect_uri={Callback URL}</span>\n<span class=\"grvsc-line\">&scope={Scope}</span>\n<span class=\"grvsc-line\">&response_type=code</span>\n<span class=\"grvsc-line\">&state={random long string}</span>\n<span class=\"grvsc-line\">&code_challenge={code challenge}</span>\n<span class=\"grvsc-line\">&code_challenge_method=SHA256</span></code></pre>\n<p>The provider should redirect you to the authentication/login page and where you’ll get the code after successful authentication.</p>\n<h3 id=\"code-exchange\" style=\"position:relative;\"><a href=\"#code-exchange\" aria-label=\"code exchange permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Code Exchange</h3>\n<p>In the code exchange request, we need to pass the code we have received through the above request and the code verifier that we have generated in our first step.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">POST Provider + /oauth/access_token</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">Request body:</span>\n<span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">   client_id:{client_id},</span>\n<span class=\"grvsc-line\">   client_secret:{client_secret},</span>\n<span class=\"grvsc-line\">   redirect_uri:{redirect_uri},</span>\n<span class=\"grvsc-line\">   response_type:token,</span>\n<span class=\"grvsc-line\">   Code:{code} // That we have received in authorization request</span>\n<span class=\"grvsc-line\">   code_verifier: {code verifier // generated in the first step</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<p>Once the code<em>verificer hash matches with the code</em>challenge of the authorization request, You will get the token in the response with status code 200 OK.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">    &quot;access_token&quot;: &quot;c5a****b-****-4*7f-a********e4a&quot;,</span>\n<span class=\"grvsc-line\">    &quot;token_type&quot;: &quot;access_token&quot;,</span>\n<span class=\"grvsc-line\">    &quot;refresh_token&quot;: &quot;5*****82-b***-**82-8c*1-*******7ce&quot;,</span>\n<span class=\"grvsc-line\">    &quot;expires_in&quot;: 11972</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<p>That's it and you've implemented PKCE flow in your application.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk5 { color: #D16969; }\n  .dark-default-dark .mtk6 { color: #D7BA7D; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n</style>","frontmatter":{"date":"September 03, 2020","updated_date":null,"title":"PKCE: What it is and how to use it with OAuth 2.0","tags":["PKCE","Oauth","OIDC"],"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/7ba5011bcf44e895dd050e8766d4d005/2a4de/pkce.png","srcSet":"/static/7ba5011bcf44e895dd050e8766d4d005/69585/pkce.png 200w,\n/static/7ba5011bcf44e895dd050e8766d4d005/497c6/pkce.png 400w,\n/static/7ba5011bcf44e895dd050e8766d4d005/2a4de/pkce.png 600w","sizes":"(max-width: 600px) 100vw, 600px"}}},"author":{"id":"Narendra Pareek","github":"pareek-narendra","avatar":null}}}}]}},"pageContext":{"tag":"OIDC"}},"staticQueryHashes":["1171199041","1384082988","2100481360","23180105","528864852"]}