<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Phase Two</title>
    <description>The latest articles on DEV Community by Phase Two (@phasetwo).</description>
    <link>https://dev.to/phasetwo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F7314%2Fbe71ed4a-f28c-4c9c-afe7-9bc57306a5a6.png</url>
      <title>DEV Community: Phase Two</title>
      <link>https://dev.to/phasetwo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/phasetwo"/>
    <language>en</language>
    <item>
      <title>Securing Angular Apps with Keycloak</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Fri, 02 Aug 2024 21:52:26 +0000</pubDate>
      <link>https://dev.to/phasetwo/securing-angular-apps-with-keycloak-98o</link>
      <guid>https://dev.to/phasetwo/securing-angular-apps-with-keycloak-98o</guid>
      <description>&lt;p&gt;In this article we'll be using &lt;a href="https://www.keycloak.org/" rel="noopener noreferrer"&gt;Keycloak&lt;/a&gt; to quickly secure a Angular application with user management and single sign on (SSO) using the open source IAMs Keycloak for Authentication and Authorization. We will demonstrate the integration by securing a page for logged-in users. This quickly provides a jump-off point to more complex integrations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/" rel="noopener noreferrer"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/" rel="noopener noreferrer"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/" rel="noopener noreferrer"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you just want to skip to the code, visit the Phase Two &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/angular" rel="noopener noreferrer"&gt;Angular example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to see a live example, visit the &lt;a href="https://phasetwo-angular-example.vercel.app" rel="noopener noreferrer"&gt;Phase Two Angular example&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  TOC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keycloak Setup&lt;/li&gt;
&lt;li&gt;Angular&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Setting up a Keycloak Instance &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;br&gt;
If you already have a functioning Keycloak instance, you can skip to the next section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;strong&gt;Keycloak Setup Details&lt;/strong&gt;
  &lt;br&gt;
Rather than trying to set up a "from scratch" instance of Keycloak, we're going to short-circuit that process by leveraging a Phase Two &lt;a href="https://phasetwo.io/" rel="noopener noreferrer"&gt;free Keycloak&lt;/a&gt; starter instance. The Starter provides a free hosted instance of Phase Two's enhanced Keycloak ready for light production use cases.

&lt;ul&gt;
&lt;li&gt;Visit the sign-up &lt;a href="https://phasetwo.io/dashboard/" rel="noopener noreferrer"&gt;page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter an email, use a Github account, or use an existing Google account to register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1jovhdjmmnys3kjp1wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1jovhdjmmnys3kjp1wb.png" alt="Register"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the register steps. This will include a sign-in link being sent to your email. Use that for password-less login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs73nhw4jl43li164nm5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs73nhw4jl43li164nm5i.png" alt="Email Link"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creating an account, a &lt;a href="https://www.youtube.com/watch?v=ZTFlc-3pG1M" rel="noopener noreferrer"&gt;realm&lt;/a&gt; is automatically created for you with all of the Phase Two enhancements. You need to create a Deployment in the Shared Phase Two infrastructure in order to gain access to the realm. Without a deployment created, the Create Shared Deployment modal will automatically pop up.&lt;/li&gt;
&lt;li&gt;Create a Shared Deployment by providing a region (pick something close to your existing infrastructure), a name for the deployment, and selecting the default organization that was created for you upon account creation. Hit "Confirm" when ready. Standby while our robots get to work generating your deployment. This can take a few seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oknshhzra67byi0uxoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oknshhzra67byi0uxoz.png" alt="Create shared deployment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the deployment is created and active, you can access the Keycloak Admin console by clicking "Open Console" for that deployment. Open it now to see the console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farwn5n54hbzwocobkmzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farwn5n54hbzwocobkmzs.png" alt="Deployments"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, move on to the next step in the tutorial. We'll be coming back to the Admin Console when its time to start connecting our App to the Keycloak instance.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up an OIDC Client
&lt;/h2&gt;

&lt;p&gt;We need to create a &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#con-oidc_server_administration_guide" rel="noopener noreferrer"&gt;OpenID Connect&lt;/a&gt; Client in Keycloak for the app to communicate with. &lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;Keycloak's &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients" rel="noopener noreferrer"&gt;docs&lt;/a&gt; provide steps for how to create an OIDC client and all the various configurations that can be introduced. Follow the steps below to create a client and get the right information necessary for app configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Create client&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Leave &lt;strong&gt;Client type&lt;/strong&gt; set to &lt;strong&gt;OpenID Connect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Enter a &lt;strong&gt;Client ID&lt;/strong&gt;. This ID is an alphanumeric string that is used in OIDC requests and in the Keycloak database to identify the client.&lt;/li&gt;
&lt;li&gt; Supply a &lt;strong&gt;Name&lt;/strong&gt; for the client.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vmlbu0gbf3wdmmacy23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vmlbu0gbf3wdmmacy23.png" alt="General settings"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Under the Capability Config section, leave the defaults as selected. This can be configured further later.&lt;/li&gt;
&lt;li&gt;Client authentication to Off.&lt;/li&gt;
&lt;li&gt;Authorization to Off.&lt;/li&gt;
&lt;li&gt;Standard flow checked. Direct access grants checked. All other items unchecked.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9fpa1jgny2300c6btd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9fpa1jgny2300c6btd.png" alt="Capbility config"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under Login settings we need to add a redirect URI and Web origin in order. Assuming you are using the example application:&lt;br&gt;
&lt;strong&gt;URI and Origin Details&lt;/strong&gt;&lt;br&gt;
The choice of &lt;code&gt;localhost&lt;/code&gt; is arbitrary. If you are using an example application running locally, this will apply. If you are using an app that you actually have deployed somewhere, then you will need to substitute the appropriate URI for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Valid redirect URI&lt;/em&gt; (allows redirect back to application)&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

http://localhost:3000/*
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    _Web origins_ (allows for Token auth call)
    ```


    http://localhost:3000


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt; Click &lt;strong&gt;Save&lt;/strong&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk6j7sjbv2b5ns7jc85a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk6j7sjbv2b5ns7jc85a.png" alt="Login settings"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;
&lt;h3&gt;
  
  
  OIDC Config
&lt;/h3&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;We will need values to configure our application. To get these values follow the instructions below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt;Find the Client you just created and click on it. In the top right click the &lt;strong&gt;Action&lt;/strong&gt; dropdown and select &lt;strong&gt;Download adapter config&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Keycloak OIDC JSON&lt;/strong&gt; in the format option. The details section will populate with the details we will need.

&lt;ul&gt;
&lt;li&gt;Note the &lt;code&gt;realm&lt;/code&gt;, &lt;code&gt;auth-server-url&lt;/code&gt;, and &lt;code&gt;resource&lt;/code&gt; values.
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjxmpf25hhyogdno2yht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjxmpf25hhyogdno2yht.png" alt="Adapter config"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Non-Admin User
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
It is bad practice to use your Admin user to sign in to an Application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we do not want to use our Admin user for signing into the app we will build, we need to add another non-admin user.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Users&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Add user&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Fill out the information for Email, First name, and Last name. Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; We will now set the password for this user manually. Click &lt;strong&gt;Credentials&lt;/strong&gt; (tab) and click &lt;strong&gt;Set Password&lt;/strong&gt;. Provide a password for this user. For our use case, as a tutorial, you can leave "Temporary" set to "Off".&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Save&lt;/strong&gt; and confirm the password by clicking &lt;strong&gt;Save password&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular &lt;a href="angular"&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
We will use the Phase Two Angular example code here, but the logic could easily be applied to any existing application.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Clone the Phase Two &lt;a href="https://github.com/p2-inc/examples/" rel="noopener noreferrer"&gt;example repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Open the Angular &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/angular" rel="noopener noreferrer"&gt;folder&lt;/a&gt; within &lt;code&gt;/frameworks/angular&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; and then &lt;code&gt;npm run start&lt;/code&gt;. This example leverages &lt;a href="https://github.com/manfredsteyer/angular-oauth2-oidc" rel="noopener noreferrer"&gt;angular-oauth2-oidc&lt;/a&gt; OIDC methods.&lt;/li&gt;
&lt;li&gt;We'll review where we configure out Keycloak instance. Open the &lt;code&gt;src/app/auth.config.ts&lt;/code&gt; file. We will be updating a few values from the prior section where we set up our OIDC client. Taking the values from the OIDC Client Config section, set those values in the code.
```tsx
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;export const authCodeFlowConfig: AuthConfig = {&lt;br&gt;
  // Update this with the url and realm of your hosted Keycloak instance&lt;br&gt;
  issuer: "&lt;a href="https://app.phasetwo.io/auth/realms/p2examples" rel="noopener noreferrer"&gt;https://app.phasetwo.io/auth/realms/p2examples&lt;/a&gt;",&lt;br&gt;
  redirectUri: window.location.origin + "/index.html",&lt;br&gt;
  // Update this to the Client ID you created in the OIDC Client section&lt;br&gt;
  clientId: "angular",&lt;br&gt;
  responseType: "code",&lt;br&gt;
  scope: "openid profile email offline_access",&lt;br&gt;
  showDebugInformation: true,&lt;br&gt;
};&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Those are used to configure the `oauthService` in the `src/app/user/user.component.ts` file. In the constructor of the component, this is passed in.
```tsx


// ...
constructor(private oauthService: OAuthService) {
  this.oauthService.configure(authCodeFlowConfig);

  // required to initialize the client
  this.oauthService.loadDiscoveryDocumentAndTryLogin();
  this.oauthService.setupAutomaticSilentRefresh();

  this.oauthService.events
    .pipe(filter((e) =&amp;gt; e.type === 'token_received'))
    .subscribe((_) =&amp;gt; this.oauthService.loadUserProfile());
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;UserActivation.component.ts&lt;/code&gt; file contains additional methods that will assist with the interaction of the html template.
For handling login and logout, the following methods are used:
```tsx
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;signIn() {&lt;br&gt;
    return this.oauthService.initLoginFlow();&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;signOut() {&lt;br&gt;
    return this.oauthService.logOut();&lt;br&gt;
  }&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while we also define additional helper methods to get user information (username, email, etc) along with raw Token values. A couple are provided below as an example.
```tsx


get userName(): string {
  const claims = this.oauthService.getIdentityClaims();
  if (!claims) return '';
  return claims['given_name'];
}

get idToken(): string {
  const token = this.oauthService.getIdToken();
  if (token) {
    return this.decodeAndStringifyToken(token);
  }
  return '';
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Switching to the html template for the user component, &lt;code&gt;src/app/user/user.component.html&lt;/code&gt;, we can see how the login and logout buttons are rendered. The buttons are conditionally rendered based on the user's authentication status based on the presence of the &lt;code&gt;idToken&lt;/code&gt;.
```html
&lt;/li&gt;
&lt;/ol&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The logic using the authenticator to conditionally determine the Authenticated state, can be used to secure routes, components, and more.
1. Open [localhost:4200](http://localhost:4200). You will see the Phase Two example landing page. You current state should be **Not authenticated**. Click **Log In**. This will redirect you to your login page.
&amp;gt; **INFO**
Use the non-admin user created in the previous section to sign in.

1. Enter the credentials of the non-admin user you created. Click **Submit**. You will then be redirected to the application. The Phase Two example landing page now loads your **Authenticated** state, displaying your user's email and name.
12. Neat! If you clear the browser state for that tab, then you will have to be redirected away to sign-in again.

## Learning more

Phase Two's enhanced Keycloak provides many ways to quickly control and tweak the log in and user management experience. Our [blog](https://phasetwo.io/blog) has many use cases from [customizing login pages](https://phasetwo.io/blog/customizing-login-pages), setting up [magic links](https://phasetwo.io/blog/set-up-magic-links) (password-less sign in), and [Organization](https://phasetwo.io/product/organizations) workflows.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>angular</category>
      <category>keycloak</category>
      <category>sso</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Securing an Angular and Spring Boot Application with Keycloak</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Wed, 22 May 2024 02:46:48 +0000</pubDate>
      <link>https://dev.to/phasetwo/securing-an-angular-and-spring-boot-application-with-keycloak-2oj6</link>
      <guid>https://dev.to/phasetwo/securing-an-angular-and-spring-boot-application-with-keycloak-2oj6</guid>
      <description>&lt;p&gt;&lt;a href="https://spring.io/projects/spring-boot"&gt;Spring Boot&lt;/a&gt; is a open-source tool which uses Java-based frameworks for building web applications.&lt;/p&gt;

&lt;p&gt;In this article we'll be using &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; to secure an &lt;a href="https://angular.io/"&gt;Angular&lt;/a&gt; application and access secured resources from a Spring Boot Web application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you just want to skip to the code, visit the Phase Two &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/spring-boot-keycloak"&gt;Spring Boot example&lt;/a&gt;. We are also building &lt;a href="https://github.com/p2-inc/examples"&gt;Keycloak examples&lt;/a&gt; for other frameworks.&lt;/p&gt;
&lt;h2&gt;
  
  
  TOC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Spring Boot Quick Start&lt;/li&gt;
&lt;li&gt;Keycloak Setup&lt;/li&gt;
&lt;li&gt;Spring Boot Configure&lt;/li&gt;
&lt;li&gt;Angular&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Setting up a Spring Boot project &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In order to setup a Spring Boot project, a JDK version must be chosen. As of the time of writing, to be inline with the latest changes from Keycloak 24, the Java 17 baseline will be used. Other JDK versions can also be used for developing the resource server according to the preference of the developer.&lt;/p&gt;

&lt;p&gt;Starting with Spring Boot 2.x the Keycloak client adapters were deprecated. In Spring Boot 3.x we will use native functionalities of the &lt;a href="https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/index.html"&gt;&lt;code&gt;spring-boot-oauth2-resource-server&lt;/code&gt;&lt;/a&gt; to be able to configure the application security context.&lt;/p&gt;
&lt;h3&gt;
  
  
  Quick Start
&lt;/h3&gt;

&lt;p&gt;To get this project up and running locally on your computer you can clone the Phase Two &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/spring-boot-keycloak"&gt;Spring Boot example&lt;/a&gt; or follow the instructions below to generate a project from scratch.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up the Spring Boot project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To kickstart a project, we will use (and recommend) using the Spring Boot &lt;a href="https://start.spring.io/"&gt;Initializr&lt;/a&gt;, a Web-based tool that provides a simple UI to generate the project.&lt;/p&gt;

&lt;p&gt;Provide the following values to spring initializr for the project metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Group: com.example
   Artifact: spring-boot-keycloak
   Name: spring-boot-keycloak
   Description: Demo project for Spring Boot
   Package name: com.example.spring-boot-keycloak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpnqvu0v4u6ki9301bvi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpnqvu0v4u6ki9301bvi.png" alt="Spring Boot Initializer" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the required dependencies in spring initializr.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the purpose of this project we will add the following dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Oauth2 Resource Server&lt;/li&gt;
&lt;li&gt;Spring Web&lt;/li&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will result in the following lines within &lt;code&gt;build.gradle&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   implementation 'org.springframework.boot:spring-boot-starter-security'
   implementation 'org.springframework.boot:spring-boot-starter-web'
   implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate the project with those settings. Open the .zip in your preferred text editor.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setup JDK 17 for the project. Follow instructions on the &lt;a href="https://docs.oracle.com/cd/E19182-01/820-7851/inst_cli_jdk_javahome_t/"&gt;JDK setup&lt;/a&gt; page.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting up a Keycloak Instance &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;br&gt;
If you already have a functioning Keycloak instance, you can skip to the next section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;strong&gt;Keycloak Setup Details&lt;/strong&gt;
  &lt;br&gt;
Rather than trying to set up a "from scratch" instance of Keycloak, we're going to short-circuit that process by leveraging a Phase Two &lt;a href="https://phasetwo.io/"&gt;free Keycloak&lt;/a&gt; starter instance. The Starter provides a free hosted instance of Phase Two's enhanced Keycloak ready for light production use cases.

&lt;ul&gt;
&lt;li&gt;Visit the sign-up &lt;a href="https://phasetwo.io/dashboard/"&gt;page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter an email, use a Github account, or use an existing Google account to register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1jovhdjmmnys3kjp1wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1jovhdjmmnys3kjp1wb.png" alt="Register" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the register steps. This will include a sign-in link being sent to your email. Use that for password-less login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs73nhw4jl43li164nm5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs73nhw4jl43li164nm5i.png" alt="Email Link" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creating an account, a &lt;a href="https://www.youtube.com/watch?v=ZTFlc-3pG1M"&gt;realm&lt;/a&gt; is automatically created for you with all of the Phase Two enhancements. You need to create a Deployment in the Shared Phase Two infrastructure in order to gain access to the realm. Without a deployment created, the Create Shared Deployment modal will automatically pop up.&lt;/li&gt;
&lt;li&gt;Create a Shared Deployment by providing a region (pick something close to your existing infrastructure), a name for the deployment, and selecting the default organization that was created for you upon account creation. Hit "Confirm" when ready. Standby while our robots get to work generating your deployment. This can take a few seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oknshhzra67byi0uxoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oknshhzra67byi0uxoz.png" alt="Create shared deployment" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the deployment is created and active, you can access the Keycloak Admin console by clicking "Open Console" for that deployment. Open it now to see the console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farwn5n54hbzwocobkmzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farwn5n54hbzwocobkmzs.png" alt="Deployments" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, move on to the next step in the tutorial. We'll be coming back to the Admin Console when its time to start connecting our App to the Keycloak instance.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up an OIDC Client
&lt;/h2&gt;

&lt;p&gt;We need to create a &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#con-oidc_server_administration_guide"&gt;OpenID Connect&lt;/a&gt; Client in Keycloak for the app to communicate with. &lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;Keycloak's &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients"&gt;docs&lt;/a&gt; provide steps for how to create an OIDC client and all the various configurations that can be introduced. Follow the steps below to create a client and get the right information necessary for app configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Create client&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Leave &lt;strong&gt;Client type&lt;/strong&gt; set to &lt;strong&gt;OpenID Connect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Enter a &lt;strong&gt;Client ID&lt;/strong&gt;. This ID is an alphanumeric string that is used in OIDC requests and in the Keycloak database to identify the client.&lt;/li&gt;
&lt;li&gt; Supply a &lt;strong&gt;Name&lt;/strong&gt; for the client.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vmlbu0gbf3wdmmacy23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vmlbu0gbf3wdmmacy23.png" alt="General settings" width="800" height="552"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Under the Capability Config section, leave the defaults as selected. This can be configured further later.&lt;/li&gt;
&lt;li&gt;Client authentication to Off.&lt;/li&gt;
&lt;li&gt;Authorization to Off.&lt;/li&gt;
&lt;li&gt;Standard flow checked. Direct access grants checked. All other items unchecked.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9fpa1jgny2300c6btd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9fpa1jgny2300c6btd.png" alt="Capbility config" width="800" height="551"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under Login settings we need to add a redirect URI and Web origin in order. Assuming you are using the example application:&lt;br&gt;
&lt;strong&gt;URI and Origin Details&lt;/strong&gt;&lt;br&gt;
The choice of &lt;code&gt;localhost&lt;/code&gt; is arbitrary. If you are using an example application running locally, this will apply. If you are using an app that you actually have deployed somewhere, then you will need to substitute the appropriate URI for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Valid redirect URI&lt;/em&gt; (allows redirect back to application)&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000/*
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;em&gt;Web origins&lt;/em&gt; (allows for Token auth call)&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk6j7sjbv2b5ns7jc85a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk6j7sjbv2b5ns7jc85a.png" alt="Login settings" width="800" height="553"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  OIDC Config
&lt;/h3&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;We will need values to configure our application. To get these values follow the instructions below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt;Find the Client you just created and click on it. In the top right click the &lt;strong&gt;Action&lt;/strong&gt; dropdown and select &lt;strong&gt;Download adapter config&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Keycloak OIDC JSON&lt;/strong&gt; in the format option. The details section will populate with the details we will need.

&lt;ul&gt;
&lt;li&gt;Note the &lt;code&gt;realm&lt;/code&gt;, &lt;code&gt;auth-server-url&lt;/code&gt;, and &lt;code&gt;resource&lt;/code&gt; values.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjxmpf25hhyogdno2yht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjxmpf25hhyogdno2yht.png" alt="Adapter config" width="800" height="554"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Non-Admin User
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
It is bad practice to use your Admin user to sign in to an Application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we do not want to use our Admin user for signing into the app we will build, we need to add another non-admin user.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Users&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Add user&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Fill out the information for Email, First name, and Last name. Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; We will now set the password for this user manually. Click &lt;strong&gt;Credentials&lt;/strong&gt; (tab) and click &lt;strong&gt;Set Password&lt;/strong&gt;. Provide a password for this user. For our use case, as a tutorial, you can leave "Temporary" set to "Off".&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Save&lt;/strong&gt; and confirm the password by clicking &lt;strong&gt;Save password&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;/p&gt;

&lt;h2&gt;
  
  
  Install and configure Spring Boot  &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we've setup and configured Keycloak using &lt;a href="https://phasetwo.io/dashboard/"&gt;Phase Two&lt;/a&gt; and cloned or created our Spring Boot application template, we will need to configure the project to leverage the capabilities provided by Keycloak.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configure application settings&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Update your &lt;code&gt;application.yaml&lt;/code&gt; configuration file with the Keycloak security configuration (it's possible your download includes a &lt;code&gt;application.properties&lt;/code&gt; file instead).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;   &lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;application&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring-boot-keycloak&lt;/span&gt;
     &lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;oauth2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="na"&gt;resourceserver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;jwt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
             &lt;span class="na"&gt;issuer-uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$http-keycloak-url/auth/realms/$your-realm&lt;/span&gt;
             &lt;span class="na"&gt;jwk-set-uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$http-keycloak-url&lt;/code&gt; with the Keycloak URL from the Phase Two hosted Keycloak instance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$your-realm&lt;/code&gt; with the Keycloak realm created earlier in this tutorial.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are using the local Keycloak instance from the cloned example, use the local address for &lt;code&gt;$http-keycloak-url&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The below Java code omits any imports, reference our example for necessary imports or use your text editor to assist with populating the imports.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configure Spring Boot resource server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Under &lt;code&gt;src.main.java.com.springbootkeycloak&lt;/code&gt; create a new package, &lt;code&gt;config&lt;/code&gt;, and create a class &lt;code&gt;SecurityConfig.java&lt;/code&gt;. In this class, add the &lt;code&gt;HttpSecurity&lt;/code&gt; settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;   &lt;span class="nd"&gt;@Configuration&lt;/span&gt;
   &lt;span class="nd"&gt;@EnableWebSecurity&lt;/span&gt;
   &lt;span class="nd"&gt;@EnableMethodSecurity&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecurityConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

       &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;JwtClaimsConverter&lt;/span&gt; &lt;span class="n"&gt;jwtAuthConverter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

       &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SecurityConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JwtClaimsConverter&lt;/span&gt; &lt;span class="n"&gt;jwtAuthConverter&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jwtAuthConverter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jwtAuthConverter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;

       &lt;span class="nd"&gt;@Bean&lt;/span&gt;
       &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SecurityFilterChain&lt;/span&gt; &lt;span class="nf"&gt;securityFilterChain&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpSecurity&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizeHttpRequests&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authz&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                   &lt;span class="n"&gt;authz&lt;/span&gt;
                           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requestMatchers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/**"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authenticated&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
           &lt;span class="o"&gt;);&lt;/span&gt;
           &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;oauth2ResourceServer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oauth2ResourceServer&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                   &lt;span class="n"&gt;oauth2ResourceServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jwtAuthenticationConverter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwtAuthConverter&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
           &lt;span class="o"&gt;);&lt;/span&gt;
           &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;csrf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;AbstractHttpConfigurer:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;disable&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

           &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sessionManagement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sessionCreationPolicy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SessionCreationPolicy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;STATELESS&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration will make the Spring Boot act as an OAuth2 Resource Server's with JWT authentication. This configuration is part of the functionality provided by the &lt;code&gt;spring-boot-starter-oauth2-resource-server&lt;/code&gt; dependency. Read more about it's configuration &lt;a href="https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html#oauth2resourceserver-jwt-sansboot"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add JWT token convert configuration&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the same &lt;code&gt;config&lt;/code&gt; package, create another class, &lt;code&gt;JwtClaimsConverter.java&lt;/code&gt;. Add a converter for extracting the security context attributes from the &lt;code&gt;access_token&lt;/code&gt; received from Keycloak.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;   &lt;span class="nd"&gt;@Component&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JwtClaimsConverter&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Converter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Jwt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AbstractAuthenticationToken&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

       &lt;span class="nd"&gt;@Override&lt;/span&gt;
       &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;AbstractAuthenticationToken&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Jwt&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authorities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extractRealmRoles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;JwtAuthenticationToken&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authorities&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getPrincipalFromClaim&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;

       &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getPrincipalFromClaim&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Jwt&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;claimName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"preferred_username"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClaim&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;claimName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;

       &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GrantedAuthority&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;extractRealmRoles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Jwt&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClaim&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"realm_access"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
           &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
           &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
                   &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"roles"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
           &lt;span class="o"&gt;}&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SimpleGrantedAuthority&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ROLE_"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toSet&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The provided example uses the &lt;code&gt;preferred_username&lt;/code&gt; claim for populating the &lt;em&gt;principal&lt;/em&gt; of the security context and the &lt;code&gt;realm_access.roles&lt;/code&gt; to populate the &lt;em&gt;authorities&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This configuration is part of the functionality provided by the &lt;code&gt;spring-boot-starter-oauth2-resource-server&lt;/code&gt; dependency. Read more about it's configuration &lt;a href="https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html#oauth2resourceserver-jwt-authorization-extraction"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the secured API resources:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In &lt;code&gt;src.main.java.com.springbootkeycloak&lt;/code&gt; create a new package, &lt;code&gt;web&lt;/code&gt;, and create a new class &lt;code&gt;TestController.java&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To test the security integration two resource endpoints are defined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/api/test/anonymous&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/api/test/user&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implemented with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;   &lt;span class="nd"&gt;@RestController&lt;/span&gt;
   &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/test"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

       &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/anonymous"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RequestMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
       &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAnonymous&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello Anonymous"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;

       &lt;span class="nd"&gt;@PreAuthorize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hasRole('ROLE_user')"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
       &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/user"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RequestMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
       &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
       &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello Secured with user role."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because both endpoints have the prefix &lt;code&gt;/api&lt;/code&gt; they will require a secure context in order to access them. Furthermore, the &lt;code&gt;/api/test/user&lt;/code&gt; endpoint is secured using a predefined authority &lt;code&gt;ROLE_user&lt;/code&gt;. This is a Realm role that can be created and applied to your example user from earlier in this tutorial.&lt;/p&gt;

&lt;p&gt;This logic can be used to extend access and authorization to any part of the application.&lt;/p&gt;

&lt;p&gt;Start the application running with &lt;code&gt;./gradlew bootRun&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the secured endpoints
&lt;/h3&gt;

&lt;p&gt;The secured endpoints can be tested using &lt;code&gt;curl&lt;/code&gt; with the &lt;code&gt;Authorization&lt;/code&gt; header. The &lt;code&gt;Authorization&lt;/code&gt; header must contain the &lt;code&gt;access_token&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s1"&gt;'http://localhost:8080/api/test/anonymous'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer {{$access_token}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s1"&gt;'http://localhost:8080/api/test/user'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: Bearer {{$access_token}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To generate an access token, you can use the &lt;code&gt;openid-connect/token&lt;/code&gt; endpoint from Keycloak.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s2"&gt;"https://&lt;/span&gt;&lt;span class="nv"&gt;$http&lt;/span&gt;&lt;span class="s2"&gt;-keycloak-url/auth/realms/&lt;/span&gt;&lt;span class="nv"&gt;$keycloak&lt;/span&gt;&lt;span class="s2"&gt;-realm/protocol/openid-connect/token"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/x-www-form-urlencoded'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'username=$test-user&amp;amp;password=$password&amp;amp;grant_type=password&amp;amp;client_id=$client-name&amp;amp;client_secret=$client-secret'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substitute the values from your Keycloak instance and test user for &lt;code&gt;$http-keycloak-url&lt;/code&gt;, &lt;code&gt;$keycloak-realm&lt;/code&gt;, &lt;code&gt;$test-user&lt;/code&gt;, &lt;code&gt;$password&lt;/code&gt;, &lt;code&gt;$client-name&lt;/code&gt;, and &lt;code&gt;$client-secret&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the returned HTTP response, the &lt;code&gt;access_token&lt;/code&gt; will be present. Use this token to test the secured endpoints in the example curl's above.&lt;/p&gt;

&lt;p&gt;At this point, your Spring Boot application is secured with Keycloak, but there is no "Frontend" to the application. In the next section, we will add an Angular SPA to demonstrate sign-in with Keycloak.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration with Angular &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In order to access the secured resources of the Spring Boot server, we will create a client application which will authenticate our users. After Authentication, that user will then have access to the secured resources via their JWT token.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate Angular Application
&lt;/h3&gt;

&lt;p&gt;Our &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/spring-boot-keycloak"&gt;Spring Boot example&lt;/a&gt; already has a basic Angular application setup. We will use that for the rest of this setup.&lt;/p&gt;

&lt;p&gt;In the example folder, open the &lt;code&gt;angularclient&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;If you do want to start your own Application, follow the instructions below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup a new Angular application following these &lt;a href="https://angular.io/start"&gt;instructions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use the Angular Oauth2 OIDC &lt;a href="https://github.com/manfredsteyer/angular-oauth2-oidc"&gt;library&lt;/a&gt; to integrate authentication and authorization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Securing views
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;/angularclient/src/app&lt;/code&gt; folder, the &lt;code&gt;app.module.ts&lt;/code&gt; file is the entry point for the Angular application. The Angular application will need to be configured in order to access user information only after authentication.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;MainpageComponent&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;BrowserModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;AppRoutingModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;FormsModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;HttpClientModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;OAuthModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APP_INITIALIZER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;applicationInitializerFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OAuthService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LOCAL_STORAGE_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;localStorageFactory&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OAuthStorage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;localStorageFactory&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app is initialized with the &lt;code&gt;OAuthService&lt;/code&gt; as a dependency. Tokens from the &lt;code&gt;OAuthService&lt;/code&gt; are stored in the browser's &lt;code&gt;localStorage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To configure the &lt;code&gt;OAuthService&lt;/code&gt;'s &lt;code&gt;authorization code&lt;/code&gt; login flow with the &lt;code&gt;angular-oauth2-oidc&lt;/code&gt; library add the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;oauthService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// URL of the SPA to redirect the user to after login&lt;/span&gt;
    &lt;span class="na"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// The SPA's id. The SPA is registered with this id at the auth-server&lt;/span&gt;
    &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$your-public-keycloak-client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// set the scope for the permissions the client should request&lt;/span&gt;
    &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// url for  /.well-known/openid-configuration endpoint&lt;/span&gt;
    &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://$http-keycloak-url:8888/auth/realms/$your-keycloak-realm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;disablePKCE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;//initialize the code flow&lt;/span&gt;
    &lt;span class="na"&gt;responseType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;showDebugInformation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;http-keycloak-url&lt;/code&gt;, &lt;code&gt;$your-public-keycloak-client&lt;/code&gt;, and &lt;code&gt;$your-keycloak-realm&lt;/code&gt; with your actual Keycloak configurations.&lt;/p&gt;

&lt;p&gt;Start the application with &lt;code&gt;npm run start&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  User Authentication
&lt;/h4&gt;

&lt;p&gt;In the &lt;code&gt;user.component.html&lt;/code&gt; file, we authenticate the user to the logged in state and conditionally render the login and logout buttons.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"isLoggedIn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Content for logged-in users --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mb-2 text-p2blue-700 text-2xl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Authenticated&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mb-6 text-p2blue-700 text-md"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"userInfo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Username&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;: {{ userInfo.username }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;: {{ userInfo.email }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Roles&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;: {{ userInfo.roles }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;[class]=&lt;/span&gt;&lt;span class="s"&gt;"buttonClasses"&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"signOut()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Sign Out&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"!isLoggedIn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mb-6 text-p2blue-700 text-2xl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Not authenticated.&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;[class]=&lt;/span&gt;&lt;span class="s"&gt;"buttonClasses"&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"signIn()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Sign In&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the &lt;code&gt;isLoggedIn&lt;/code&gt; function can be found in the &lt;code&gt;user.component.ts&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoggedIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oauthService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasValidAccessToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clicking the Log In or Log Out buttons will redirect to the Keycloak login page or log the user out.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use Angular guards to secure routes
&lt;/h4&gt;

&lt;p&gt;We can achieve route restriction by using guards. If the access token is not valid the guard will initiate the login flow. You could optionally apply this at the router level to enforce a full page login.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthGuard&lt;/span&gt; &lt;span class="kr"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;oauthService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OAuthService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActivatedRouteSnapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RouterStateSnapshot&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;UrlTree&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oauthService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasValidAccessToken&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oauthService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initLoginFlow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Learning more
&lt;/h2&gt;

&lt;p&gt;Phase Two's enhanced Keycloak provides many ways to quickly control and tweak the log in and user management experience. Our &lt;a href="https://phasetwo.io/blog"&gt;blog&lt;/a&gt; has many use cases from &lt;a href="https://phasetwo.io/blog/customizing-login-pages"&gt;customizing login pages&lt;/a&gt;, setting up &lt;a href="https://phasetwo.io/blog/set-up-magic-links"&gt;magic links&lt;/a&gt; (password-less sign in), and &lt;a href="https://phasetwo.io/product/organizations"&gt;Organization&lt;/a&gt; workflows.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>authentication</category>
      <category>keycloak</category>
      <category>angular</category>
    </item>
    <item>
      <title>Securing SvelteKit Apps with Keycloak</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Tue, 07 May 2024 03:02:59 +0000</pubDate>
      <link>https://dev.to/phasetwo/securing-sveltekit-apps-with-keycloak-1f9c</link>
      <guid>https://dev.to/phasetwo/securing-sveltekit-apps-with-keycloak-1f9c</guid>
      <description>&lt;p&gt;&lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; and specifically, &lt;a href="https://kit.svelte.dev/"&gt;SvelteKit&lt;/a&gt; is an open source web framework that makes developing web applications easier.&lt;/p&gt;

&lt;p&gt;In this article we'll be using &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; to quickly augment an application with user management and SSO. We will demonstrate the integration by securing a page for logged-in users. This quickly provides a jump-off point to more complex integrations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
If you just want to skip to the code, visit the Phase Two &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/sveltekit"&gt;SvelteKit example&lt;/a&gt;. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  TOC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keycloak Setup&lt;/li&gt;
&lt;li&gt;SvelteKit&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Setting up a Keycloak Instance &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;br&gt;
If you already have a functioning Keycloak instance, you can skip to the next section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;strong&gt;Keycloak Setup Details&lt;/strong&gt;
  &lt;br&gt;
Rather than trying to set up a "from scratch" instance of Keycloak, we're going to short-circuit that process by leveraging a Phase Two &lt;a href="https://phasetwo.io/"&gt;free Keycloak&lt;/a&gt; starter instance. The Starter provides a free hosted instance of Phase Two's enhanced Keycloak ready for light production use cases.

&lt;ul&gt;
&lt;li&gt;Visit the sign-up &lt;a href="https://phasetwo.io/dashboard/"&gt;page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter an email, use a Github account, or use an existing Google account to register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1jovhdjmmnys3kjp1wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1jovhdjmmnys3kjp1wb.png" alt="Register" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the register steps. This will include a sign-in link being sent to your email. Use that for password-less login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs73nhw4jl43li164nm5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs73nhw4jl43li164nm5i.png" alt="Email Link" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creating an account, a &lt;a href="https://www.youtube.com/watch?v=ZTFlc-3pG1M"&gt;realm&lt;/a&gt; is automatically created for you with all of the Phase Two enhancements. You need to create a Deployment in the Shared Phase Two infrastructure in order to gain access to the realm. Without a deployment created, the Create Shared Deployment modal will automatically pop up.&lt;/li&gt;
&lt;li&gt;Create a Shared Deployment by providing a region (pick something close to your existing infrastructure), a name for the deployment, and selecting the default organization that was created for you upon account creation. Hit "Confirm" when ready. Standby while our robots get to work generating your deployment. This can take a few seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oknshhzra67byi0uxoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oknshhzra67byi0uxoz.png" alt="Create shared deployment" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the deployment is created and active, you can access the Keycloak Admin console by clicking "Open Console" for that deployment. Open it now to see the console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farwn5n54hbzwocobkmzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farwn5n54hbzwocobkmzs.png" alt="Deployments" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, move on to the next step in the tutorial. We'll be coming back to the Admin Console when its time to start connecting our App to the Keycloak instance.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up an OIDC Client
&lt;/h2&gt;

&lt;p&gt;We need to create a &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#con-oidc_server_administration_guide"&gt;OpenID Connect&lt;/a&gt; Client in Keycloak for the app to communicate with. &lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;Keycloak's &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients"&gt;docs&lt;/a&gt; provide steps for how to create an OIDC client and all the various configurations that can be introduced. Follow the steps below to create a client and get the right information necessary for app configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Create client&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Leave &lt;strong&gt;Client type&lt;/strong&gt; set to &lt;strong&gt;OpenID Connect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Enter a &lt;strong&gt;Client ID&lt;/strong&gt;. This ID is an alphanumeric string that is used in OIDC requests and in the Keycloak database to identify the client.&lt;/li&gt;
&lt;li&gt; Supply a &lt;strong&gt;Name&lt;/strong&gt; for the client.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vmlbu0gbf3wdmmacy23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vmlbu0gbf3wdmmacy23.png" alt="General settings" width="800" height="552"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Under the Capability Config section, leave the defaults as selected. This can be configured further later.&lt;/li&gt;
&lt;li&gt;Client authentication to Off.&lt;/li&gt;
&lt;li&gt;Authorization to Off.&lt;/li&gt;
&lt;li&gt;Standard flow checked. Direct access grants checked. All other items unchecked.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9fpa1jgny2300c6btd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9fpa1jgny2300c6btd.png" alt="Capbility config" width="800" height="551"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under Login settings we need to add a redirect URI and Web origin in order. Assuming you are using the example application:&lt;br&gt;
&lt;strong&gt;URI and Origin Details&lt;/strong&gt;&lt;br&gt;
The choice of &lt;code&gt;localhost&lt;/code&gt; is arbitrary. If you are using an example application running locally, this will apply. If you are using an app that you actually have deployed somewhere, then you will need to substitute the appropriate URI for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Valid redirect URI&lt;/em&gt; (allows redirect back to application)&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000/*
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;em&gt;Web origins&lt;/em&gt; (allows for Token auth call)&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk6j7sjbv2b5ns7jc85a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk6j7sjbv2b5ns7jc85a.png" alt="Login settings" width="800" height="553"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  OIDC Config
&lt;/h3&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;We will need values to configure our application. To get these values follow the instructions below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt;Find the Client you just created and click on it. In the top right click the &lt;strong&gt;Action&lt;/strong&gt; dropdown and select &lt;strong&gt;Download adapter config&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Keycloak OIDC JSON&lt;/strong&gt; in the format option. The details section will populate with the details we will need.

&lt;ul&gt;
&lt;li&gt;Note the &lt;code&gt;realm&lt;/code&gt;, &lt;code&gt;auth-server-url&lt;/code&gt;, and &lt;code&gt;resource&lt;/code&gt; values.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjxmpf25hhyogdno2yht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjxmpf25hhyogdno2yht.png" alt="Adapter config" width="800" height="554"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Non-Admin User
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
It is bad practice to use your Admin user to sign in to an Application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we do not want to use our Admin user for signing into the app we will build, we need to add another non-admin user.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Users&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Add user&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Fill out the information for Email, First name, and Last name. Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; We will now set the password for this user manually. Click &lt;strong&gt;Credentials&lt;/strong&gt; (tab) and click &lt;strong&gt;Set Password&lt;/strong&gt;. Provide a password for this user. For our use case, as a tutorial, you can leave "Temporary" set to "Off".&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Save&lt;/strong&gt; and confirm the password by clicking &lt;strong&gt;Save password&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a SvelteKit Project &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
We will use the Phase Two SvelteKit example code here, but the logic could easily be applied to any existing application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Clone the Phase Two &lt;a href="https://github.com/p2-inc/examples/"&gt;example repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Open the SvelteKit &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/sveltekit"&gt;folder&lt;/a&gt; within &lt;code&gt;/frameworks/sveltekit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; and then &lt;code&gt;npm run dev&lt;/code&gt;. This example leverages &lt;a href="https://github.com/nextauthjs/next-auth"&gt;@auth/sveltekit&lt;/a&gt; to provide HOC support.&lt;/li&gt;
&lt;li&gt;The project makes use of the following SvelteKit items: hooks, components, layout, and &lt;code&gt;@auth/sveltekit&lt;/code&gt; module. We'll review each in kind.&lt;/li&gt;
&lt;li&gt;We'll review where we configure out Keycloak instance. Open the &lt;code&gt;src/auth.ts&lt;/code&gt; file. This is a server only file. We will be updating a few values from the prior section where we set up our OIDC client. Taking the values from the OIDC Client Config section, set those values in the code. While it is recommended to use Environment variables for the secret, for the purpose of this tutorial, paste in the &lt;strong&gt;Client secret&lt;/strong&gt; from the OIDC client creation section for the value of &lt;code&gt;clientSecret&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Use Environment Variables AUTH_SECRET in prod&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authjsSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;f18d48ce9bea32e44b5591b2c89185729d4559435f77ca76872a83a0850563a4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;realm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared-deployment-001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kcConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Use Environment Variables AUTH_KEYCLOAK_ISSUER in prod&lt;/span&gt;
  &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://usw2.auth.ac/auth/realms/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;realm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Paste "Client id" here. Use Environment Variables AUTH_KEYCLOAK_ID in prod&lt;/span&gt;
  &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reg-example-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Paste "Client secret" here. Use Environment Variables AUTH_KEYCLOAK_ISSUER in prod&lt;/span&gt;
  &lt;span class="na"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CLIENT_SECRET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Those are used to popluate the config for the provider &lt;code&gt;Keycloak&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signOut&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SvelteKitAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;trustHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;authjsSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Keycloak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kcConfig&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Next, let's review the hooks (&lt;code&gt;src/hooks.server.ts&lt;/code&gt;) file. This imports the &lt;code&gt;handle&lt;/code&gt; method by the &lt;code&gt;src/auth.ts&lt;/code&gt; and re-exports it. This allows the hooks to act as a middleware and include the authentication status of the user in each request.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./auth.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;To retrieve the authentication status of the user in server-side rendering on the index route, it's using the &lt;code&gt;+layout.server.ts&lt;/code&gt; file. It retrieves the authentication status via the &lt;code&gt;getSession&lt;/code&gt; function from &lt;a href="https://kit.svelte.dev/docs/types#app-locals"&gt;SvelteKit Locals&lt;/a&gt; set by &lt;code&gt;src/hook.server.ts&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LayoutServerLoad&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./$types.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LayoutServerLoad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;The server-side authentication data is then accessed inside the &lt;code&gt;+page.svelte&lt;/code&gt;, and then passed onto the user (&lt;code&gt;src/components/user.svelte&lt;/code&gt;) component as follows:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$components/user.svelte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LayoutServerData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./$types.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LayoutServerData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

// ... Rest of the index route ... // &lt;span class="nt"&gt;&amp;lt;User&lt;/span&gt; &lt;span class="na"&gt;data=&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;user:&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;session&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;status:&lt;/span&gt; &lt;span class="na"&gt;Boolean&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="err"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;session&lt;/span&gt;&lt;span class="err"&gt;),&lt;/span&gt; &lt;span class="err"&gt;}}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The props, &lt;strong&gt;user&lt;/strong&gt; and &lt;strong&gt;status&lt;/strong&gt; represent the user information object and whether the user is signed in, respectively.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;At this point our entire application will be able to access all information and methods needed to perform authentication. View &lt;code&gt;src/components/user.svelte&lt;/code&gt; for exactly how the code is authenticating your user. The sections rendering the &lt;strong&gt;Log in&lt;/strong&gt; and &lt;strong&gt;Log out&lt;/strong&gt; buttons are conditional areas based on the authenticated context. The buttons invoke server-side APIs provided by &lt;code&gt;@auth/sveltekit&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The logic using the authenticator to conditionally determine the Authenticated state, can be used to secure routes, components, and more.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="http://localhost:3000"&gt;localhost:3000&lt;/a&gt;. You will see the Phase Two example landing page. You current state should be &lt;strong&gt;Not authenticated&lt;/strong&gt;. Click &lt;strong&gt;Log In&lt;/strong&gt;. This will redirect you to your login page.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
Use the non-admin user created in the previous section to sign in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Enter the credentials of the non-admin user you created. Click &lt;strong&gt;Submit&lt;/strong&gt;. You will then be redirected to the application. The Phase Two example landing page now loads your &lt;strong&gt;Authenticated&lt;/strong&gt; state, displaying your user's email and name.&lt;/li&gt;
&lt;li&gt;Neat! If you clear the browser state for that tab, then you will have to be redirected away to sign-in again.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Learning more
&lt;/h2&gt;

&lt;p&gt;Phase Two's enhanced Keycloak provides many ways to quickly control and tweak the log in and user management experience. Our &lt;a href="https://phasetwo.io/blog"&gt;blog&lt;/a&gt; has many use cases from &lt;a href="https://phasetwo.io/blog/customizing-login-pages"&gt;customizing login pages&lt;/a&gt;, setting up &lt;a href="https://phasetwo.io/blog/set-up-magic-links"&gt;magic links&lt;/a&gt; (password-less sign in), and &lt;a href="https://phasetwo.io/product/organizations"&gt;Organization&lt;/a&gt; workflows.&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>sso</category>
      <category>svelte</category>
      <category>keycloak</category>
    </item>
    <item>
      <title>Securing Remix Apps with Keycloak</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Tue, 07 May 2024 02:45:41 +0000</pubDate>
      <link>https://dev.to/phasetwo/securing-remix-apps-with-keycloak-43mc</link>
      <guid>https://dev.to/phasetwo/securing-remix-apps-with-keycloak-43mc</guid>
      <description>&lt;p&gt;&lt;a href="https://remix.run/"&gt;Remix&lt;/a&gt; is an open source web framework that makes developing web applications easier.&lt;/p&gt;

&lt;p&gt;In this article we'll be using &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; to quickly augment an application with user management and SSO. We will demonstrate the integration by securing a page for logged-in users. This quickly provides a jump-off point to more complex integrations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
If you just want to skip to the code, visit the Phase Two &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/remix"&gt;Remix example&lt;/a&gt;. We also have a plain &lt;a href="https://phasetwo.io/blog/instant-user-managemenet-and-sso-for-reactjs"&gt;React example&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  TOC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keycloak Setup&lt;/li&gt;
&lt;li&gt;Remix&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Setting up a Keycloak Instance &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;br&gt;
If you already have a functioning Keycloak instance, you can skip to the next section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;strong&gt;Keycloak Setup Details&lt;/strong&gt;
  &lt;br&gt;
Rather than trying to set up a "from scratch" instance of Keycloak, we're going to short-circuit that process by leveraging a Phase Two &lt;a href="https://phasetwo.io/"&gt;free Keycloak&lt;/a&gt; starter instance. The Starter provides a free hosted instance of Phase Two's enhanced Keycloak ready for light production use cases.

&lt;ul&gt;
&lt;li&gt;Visit the sign-up &lt;a href="https://phasetwo.io/dashboard/"&gt;page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter an email, use a Github account, or use an existing Google account to register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1jovhdjmmnys3kjp1wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1jovhdjmmnys3kjp1wb.png" alt="Register" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the register steps. This will include a sign-in link being sent to your email. Use that for password-less login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs73nhw4jl43li164nm5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs73nhw4jl43li164nm5i.png" alt="Email Link" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creating an account, a &lt;a href="https://www.youtube.com/watch?v=ZTFlc-3pG1M"&gt;realm&lt;/a&gt; is automatically created for you with all of the Phase Two enhancements. You need to create a Deployment in the Shared Phase Two infrastructure in order to gain access to the realm. Without a deployment created, the Create Shared Deployment modal will automatically pop up.&lt;/li&gt;
&lt;li&gt;Create a Shared Deployment by providing a region (pick something close to your existing infrastructure), a name for the deployment, and selecting the default organization that was created for you upon account creation. Hit "Confirm" when ready. Standby while our robots get to work generating your deployment. This can take a few seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oknshhzra67byi0uxoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oknshhzra67byi0uxoz.png" alt="Create shared deployment" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the deployment is created and active, you can access the Keycloak Admin console by clicking "Open Console" for that deployment. Open it now to see the console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farwn5n54hbzwocobkmzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farwn5n54hbzwocobkmzs.png" alt="Deployments" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, move on to the next step in the tutorial. We'll be coming back to the Admin Console when its time to start connecting our App to the Keycloak instance.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up an OIDC Client
&lt;/h2&gt;

&lt;p&gt;We need to create a &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#con-oidc_server_administration_guide"&gt;OpenID Connect&lt;/a&gt; Client in Keycloak for the app to communicate with. &lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;Keycloak's &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients"&gt;docs&lt;/a&gt; provide steps for how to create an OIDC client and all the various configurations that can be introduced. Follow the steps below to create a client and get the right information necessary for app configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Create client&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Leave &lt;strong&gt;Client type&lt;/strong&gt; set to &lt;strong&gt;OpenID Connect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Enter a &lt;strong&gt;Client ID&lt;/strong&gt;. This ID is an alphanumeric string that is used in OIDC requests and in the Keycloak database to identify the client.&lt;/li&gt;
&lt;li&gt; Supply a &lt;strong&gt;Name&lt;/strong&gt; for the client.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vmlbu0gbf3wdmmacy23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vmlbu0gbf3wdmmacy23.png" alt="General settings" width="800" height="552"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Under the Capability Config section, leave the defaults as selected. This can be configured further later.&lt;/li&gt;
&lt;li&gt;Client authentication to Off.&lt;/li&gt;
&lt;li&gt;Authorization to Off.&lt;/li&gt;
&lt;li&gt;Standard flow checked. Direct access grants checked. All other items unchecked.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9fpa1jgny2300c6btd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9fpa1jgny2300c6btd.png" alt="Capbility config" width="800" height="551"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under Login settings we need to add a redirect URI and Web origin in order. Assuming you are using the example application:&lt;br&gt;
&lt;strong&gt;URI and Origin Details&lt;/strong&gt;&lt;br&gt;
The choice of &lt;code&gt;localhost&lt;/code&gt; is arbitrary. If you are using an example application running locally, this will apply. If you are using an app that you actually have deployed somewhere, then you will need to substitute the appropriate URI for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Valid redirect URI&lt;/em&gt; (allows redirect back to application)&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000/*
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;em&gt;Web origins&lt;/em&gt; (allows for Token auth call)&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk6j7sjbv2b5ns7jc85a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk6j7sjbv2b5ns7jc85a.png" alt="Login settings" width="800" height="553"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  OIDC Config
&lt;/h3&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;We will need values to configure our application. To get these values follow the instructions below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt;Find the Client you just created and click on it. In the top right click the &lt;strong&gt;Action&lt;/strong&gt; dropdown and select &lt;strong&gt;Download adapter config&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Keycloak OIDC JSON&lt;/strong&gt; in the format option. The details section will populate with the details we will need.

&lt;ul&gt;
&lt;li&gt;Note the &lt;code&gt;realm&lt;/code&gt;, &lt;code&gt;auth-server-url&lt;/code&gt;, and &lt;code&gt;resource&lt;/code&gt; values.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjxmpf25hhyogdno2yht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjxmpf25hhyogdno2yht.png" alt="Adapter config" width="800" height="554"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Non-Admin User
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
It is bad practice to use your Admin user to sign in to an Application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we do not want to use our Admin user for signing into the app we will build, we need to add another non-admin user.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Users&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Add user&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Fill out the information for Email, First name, and Last name. Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; We will now set the password for this user manually. Click &lt;strong&gt;Credentials&lt;/strong&gt; (tab) and click &lt;strong&gt;Set Password&lt;/strong&gt;. Provide a password for this user. For our use case, as a tutorial, you can leave "Temporary" set to "Off".&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Save&lt;/strong&gt; and confirm the password by clicking &lt;strong&gt;Save password&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a Remix Project &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
We will use the Phase Two Remix example code here, but the logic could easily be applied to any existing application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Clone the Phase Two &lt;a href="https://github.com/p2-inc/examples/"&gt;example repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Open the Remix &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/remix"&gt;folder&lt;/a&gt; within &lt;code&gt;/frameworks/remix&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; and then &lt;code&gt;npm run dev -- --port 3000&lt;/code&gt;. This example leverages &lt;a href="https://github.com/sergiodxa/remix-auth"&gt;remix-auth&lt;/a&gt; and &lt;a href="https://github.com/marsmars0x01/remix-keycloak"&gt;remix-keycloak&lt;/a&gt; to provide HOC support.&lt;/li&gt;
&lt;li&gt;Open the &lt;code&gt;app/services/keycloak.server.ts&lt;/code&gt; file. This is a server only file. We will be updating a few values from the prior section where we set up our OIDC client. Taking the values from the OIDC Client Config section, set those values in the code. While it is recommended to use Environment variables for the secret, for the purpose of this tutorial, paste in the &lt;strong&gt;Client secret&lt;/strong&gt; from the OIDC client creation section for the value of &lt;code&gt;clientSecret&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kcConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;useSSL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;usw2.auth.ac/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;realm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared-deployment-001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;clientID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reg-example-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CLIENT_SECRET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Paste "Client secret" here. Use Environment variables in prod&lt;/span&gt;
  &lt;span class="na"&gt;callbackURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000/auth/keycloak/callback&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Those are used to popluate the config for the &lt;code&gt;KeycloakStrategy&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KeycloakStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kcConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The config is then used with the Authenticator instance in the &lt;code&gt;app/services/auth.server.ts&lt;/code&gt; file. The authenticator instance uses the Session Storage to manage the state of authentication via a cookie.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Authenticator&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remix-auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;keycloakServer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./keycloak.server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sessionStorage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;~/services/session.server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authenticator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Authenticator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;authenticator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keycloakServer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point our entire application will be able to access all information and methods needed to perform authentication. View the &lt;code&gt;session.server.ts&lt;/code&gt; file for additional information about how the &lt;code&gt;SessionStorage&lt;/code&gt; is used. The &lt;code&gt;SessionStorage&lt;/code&gt; stores the Keycloak token and is used to derive the authenticated state. View &lt;code&gt;user.tsx&lt;/code&gt; for exactly how the code is authenticating your user. The sections rendering the &lt;strong&gt;Log in&lt;/strong&gt; and &lt;strong&gt;Log out&lt;/strong&gt; buttons are conditional areas based on the authenticated context. The buttons invoke server-side APIs provided by &lt;code&gt;remix-auth&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The logic using the authenticator to conditionally determine the Authenticated state, can be used to secure routes, components, and more.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="http://localhost:3000"&gt;localhost:3000&lt;/a&gt;. You will see the Phase Two example landing page. You current state should be &lt;strong&gt;Not authenticated&lt;/strong&gt;. Click &lt;strong&gt;Log In&lt;/strong&gt;. This will redirect you to your login page.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
   Use the non-admin user created in the previous section to sign in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Enter the credentials of the non-admin user you created. Click &lt;strong&gt;Submit&lt;/strong&gt;. You will then be redirected to the application. The Phase Two example landing page now loads your &lt;strong&gt;Authenticated&lt;/strong&gt; state, displaying your user's email and name.&lt;/li&gt;
&lt;li&gt;Neat! If you clear the browser state for that tab, then you will have to be redirected away to sign-in again.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Learning more
&lt;/h2&gt;

&lt;p&gt;Phase Two's enhanced Keycloak provides many ways to quickly control and tweak the log in and user management experience. Our &lt;a href="https://phasetwo.io/blog"&gt;blog&lt;/a&gt; has many use cases from &lt;a href="https://phasetwo.io/blog/customizing-login-pages"&gt;customizing login pages&lt;/a&gt;, setting up &lt;a href="https://phasetwo.io/blog/set-up-magic-links"&gt;magic links&lt;/a&gt; (password-less sign in), and &lt;a href="https://phasetwo.io/product/organizations"&gt;Organization&lt;/a&gt; workflows.&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>sso</category>
      <category>identityandaccessmanagement</category>
      <category>remix</category>
    </item>
    <item>
      <title>User Management and Identity Brokering for On-Prem Apps with Keycloak</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Wed, 03 Apr 2024 02:39:34 +0000</pubDate>
      <link>https://dev.to/phasetwo/user-management-and-identity-brokering-for-on-prem-apps-with-keycloak-5h28</link>
      <guid>https://dev.to/phasetwo/user-management-and-identity-brokering-for-on-prem-apps-with-keycloak-5h28</guid>
      <description>&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  User Management and Identity Brokering for On-Prem Apps
&lt;/h1&gt;

&lt;p&gt;With many companies racing into the cloud, very little is written about the huge opportunity, and potential pitfalls of building software for on-prem and private cloud deployments. With the growing Kubernetes and CNCF ecosystems, the balance point to justify self-hosting is constantly shifting. This is great news for companies that must host data and applications inside the enterprise. For software vendors looking to serve this exploding market, authentication can be a blind spot.&lt;/p&gt;

&lt;h3&gt;
  
  
  A story, inspired by customer use cases:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;You’ve built a successful enterprise SaaS product, and your cloud offering has taken off. Recently, you’ve been getting inquiries from government agencies, large companies in regulated industries, and foreign companies – all of which have legal, compliance or regulatory requirements that prohibit them from using your product in the cloud.&lt;/p&gt;

&lt;p&gt;Given the size of the opportunity, you’ve decided to go for it. Your team has packaged your application up as a set of Kubernetes manifests, making changes, replacing cloud services with open source alternatives, and even built out a runbook to help your devops peers at the customer operate it themselves.&lt;/p&gt;

&lt;p&gt;The big day comes, and you’re installing at your first customer. You expect that there will be some minor bumps along the way, but their first question just flattens you: “How do we connect this to our in-house identity provider?” It was a question that was never on your radar, but now it’s the most important thing for the customer.&lt;/p&gt;

&lt;p&gt;Like most SaaS companies, you’re probably either hand-rolling your authentication and user management using something like Passport.js, Devise, Django, etc., using some social login options, or using a cloud-only service like Auth0 or WorkOS. If you had implemented SAML, the most common protocol for just-in-time user provisioning with enterprise identity providers, you probably went for a basic approach. You wrongly assumed that user management and identity brokering would be easier for on-prem.&lt;/p&gt;

&lt;p&gt;You throw some engineering and customer success resources at the problem, but quickly realize it’s not a scalable solution. The customer wants to map their groups, and manage access and authorization through &lt;em&gt;their&lt;/em&gt; IdP. Just the overhead of connecting to every possible type of IdP, and supporting that for every customer, will eat up your margin before they start using your application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;strong&gt;good news&lt;/strong&gt; is that you’re not alone in missing this key enterprise need. Many companies who are new to on-prem and private cloud deployments learn this the hard way, many without losing customers.&lt;/p&gt;

&lt;p&gt;However, the reality is that for an application that is used by an entire enterprise, who can use it (authentication) and how (authorization) is equally as important for on-prem applications as cloud. And, being hosted and operated by your customer, simplicity of management and transparency is more important than cloud.&lt;/p&gt;

&lt;h3&gt;
  
  
  An open source solution to the rescue
&lt;/h3&gt;

&lt;p&gt;Fortunately, there is feature complete identity and access management system that is equally at home both on-premise and in the cloud. It can easily facilitate identity brokering with the customer identity provider, as well as give their IT staff access to critical access and operational information.&lt;/p&gt;

&lt;p&gt;At Phase Two, we’ve had a front row seat in solving this problem. Our customers have deployed &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt;, bundled with their application to over 300 of their customer sites. In these deployments, Keycloak is used for identity brokering to the customer identity provider, SSO authentication for all of their deployed applications, and role and access management to broker and manage authorization within their applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools to empower the customer
&lt;/h3&gt;

&lt;p&gt;In addition to solving these core challenges, Phase Two has built &lt;a href="https://github.com/p2-inc"&gt;tools&lt;/a&gt; to extend enterprise &lt;a href="https://phasetwo.io/product/organizations"&gt;use-cases&lt;/a&gt; and facilitate &lt;a href="https://phasetwo.io/product/adminportal"&gt;customer onboarding&lt;/a&gt;, one of the biggest drags on Customer Success hours, and ultimately a huge margin drain.&lt;/p&gt;

&lt;p&gt;To this end, the most valuable tool, from our customers’ perspectives is our &lt;a href="https://github.com/p2-inc/idp-wizard"&gt;Identity Provider Setup Wizard&lt;/a&gt;. This tool is meant as a guide for customers’ initial IdP connection, turning an esoteric form into a clear step-by-step process for specific IDPs (what keys to get, where to store them, and so on). This had previously been the long pole in the onboarding tent. By giving the customers a tool to self-configure and manage their own IdP connection, Phase Two has gifted back valuable Customer Success hours and margin dollars.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oDX80OzV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/p2-inc/idp-wizard/assets/244253/e9b421c0-b487-4c07-9eed-87ea89fc574b" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oDX80OzV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/p2-inc/idp-wizard/assets/244253/e9b421c0-b487-4c07-9eed-87ea89fc574b" alt="idp-wizard-video-gif" width="360" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We conveniently bundle all of these tools in &lt;a href="https://github.com/p2-inc/phasetwo-containers"&gt;Docker images&lt;/a&gt; for easy deployment. &lt;/p&gt;

&lt;p&gt;Does the above story sound familiar, or something you might be stumbling into? &lt;a href="//mailto:sales@phasetwo.io"&gt;Contact sales&lt;/a&gt; to find out how we can help your journey to on-prem be as painless as possible and supercharge your customer identity onboarding process.&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>sso</category>
      <category>identityand</category>
    </item>
    <item>
      <title>Keycloak: An open source alternative to Auth0, WorkOS, Okta, Cognito, ...</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Wed, 03 Apr 2024 02:33:40 +0000</pubDate>
      <link>https://dev.to/phasetwo/keycloak-an-open-source-alternative-to-auth0-workos-okta-cognito--19im</link>
      <guid>https://dev.to/phasetwo/keycloak-an-open-source-alternative-to-auth0-workos-okta-cognito--19im</guid>
      <description>&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In today's digital landscape, managing user identities and securing access to applications and services is paramount for businesses of all sizes. As the demand for robust identity and access management (IAM) solutions grows, so does the market, with various commercial options vying for attention. When we first started using &lt;a href="https://keycloak.org"&gt;Keycloak&lt;/a&gt; over 7 years ago, we were surprised that there was a relatively unknown, but completely open-source alternative to commercial offerings in the Identity and Access Management market.&lt;/p&gt;

&lt;h3&gt;
  
  
  Commercial offerings
&lt;/h3&gt;

&lt;p&gt;Companies such as &lt;a href="https://www.auth0.com"&gt;Auth0&lt;/a&gt;, &lt;a href="https://www.okta.com"&gt;Okta&lt;/a&gt;, Microsoft (through &lt;a href="https://www.microsoft.com/en-us/security/business/microsoft-entra"&gt;AzureAD&lt;/a&gt;) had created cloud authentication services, and helped bring standardization to the market through implementation of standards, such as OIDC, SAML, SCIM, LDAP, etc. However, there was little differentiation among them, and despite their pricing models, were essentially commodities that were the same.&lt;/p&gt;

&lt;p&gt;Amazon released &lt;a href="https://aws.amazon.com/cognito"&gt;AWS Cognito&lt;/a&gt;, which did price it as a commodity, but failed so miserably in UI and developer ergonomics, that it failed to reach a dominant market position despite its de minimis cost.&lt;/p&gt;

&lt;p&gt;More recently, nascent companies such as &lt;a href="https://workos.com"&gt;WorkOS&lt;/a&gt; and &lt;a href="https://www.frontegg.com"&gt;Frontegg&lt;/a&gt;, while casting themselves as CIAM and “SSO made easy” to enterprise SaaS customers, are really just repackaging the same IAM features and protocol implementations that have been available in Keycloak for years. Furthermore, the pricing models have tilted back towards predatory on your company’s business model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open source alternatives
&lt;/h3&gt;

&lt;p&gt;Amidst this landscape, open-source alternatives like Keycloak are emerging as powerful contenders, offering unique advantages over their commercial counterparts. Because the market has settled on standard protocols, it opened the door for superior open-source implementations to emerge with feature parity and standards compliance. Keycloak stands out as an alternative to commercial IAM solutions, enabling your business to unlock both flexibility and control.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open Source Foundation:&lt;/strong&gt; At the heart of Keycloak lies its open-source nature. Developed by Red Hat, Keycloak provides a fully-fledged IAM solution that is freely available for anyone to use, modify, and extend according to their requirements. This open ethos empowers organizations with unparalleled flexibility and control over their identity infrastructure, without being tied to proprietary vendors or licensing agreements. Furthermore, given the core security requirements of the protocol implementations, developing in the open gives customers the reassurance that the code has been audited by others, unlike closed source, buggy, commercial implementations that come with zero transparency or guarantees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost-Effectiveness:&lt;/strong&gt; One of the most significant advantages of Keycloak is its cost-effectiveness. Unlike commercial IAM solutions that operate on subscription-based pricing models, Keycloak eliminates licensing fees, enabling organizations to allocate resources more efficiently. With Keycloak, businesses can scale their identity infrastructure without worrying about escalating costs, making it an attractive option for startups, small businesses, and enterprises alike.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization and Extensibility:&lt;/strong&gt; Keycloak stands out for its robust customization and extensibility capabilities. From authentication flows and user federation to role-based access control (RBAC) and fine-grained permissions, Keycloak provides a plethora of features that can be tailored to suit specific use cases and compliance requirements. Moreover, its modular architecture and comprehensive API support facilitate seamless integration with existing systems and third-party services, empowering developers to build bespoke identity solutions with ease.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-Premise and Cloud Deployment:&lt;/strong&gt; Whether organizations prefer on-premise deployment for enhanced security and compliance or cloud-based solutions for scalability and convenience, Keycloak offers the flexibility to meet diverse deployment needs. With support for Docker, Kubernetes, and other containerization technologies, Keycloak simplifies deployment across various environments, ensuring seamless integration into existing infrastructure and workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Community and Support:&lt;/strong&gt; Backed by a vibrant community of developers and contributors, Keycloak benefits from ongoing enhancements, bug fixes, and feature additions. This active ecosystem fosters innovation and collaboration, with users sharing best practices, troubleshooting tips, and extensions through forums, mailing lists, and code repositories. Additionally, organizations seeking professional support and services can leverage expertise of a growing ecosystem of companies providing support, ensuring reliable deployment and ongoing maintenance of their Keycloak instances.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Barriers
&lt;/h3&gt;

&lt;p&gt;So, given Keycloak's inherent advantages, while solving all of the same problems, why has it failed to receive broad market adoption? Looking back, and polling our customer base, it seems that Keycloak has suffered from a couple of barriers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Awareness:&lt;/strong&gt; Other than a couple of markets (e.g. Germany) Keycloak is still relatively unknown. Because it’s not a commercial entity, there isn’t a content marketing engine that focuses on discovery for common use cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Onboarding&lt;/strong&gt;: Documentation for getting successful for common use cases is fragmented and often hard to find. When solving a new problem, examples are a great way to get a developer “hooked”, but these are largely missing from official Keycloak documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community&lt;/strong&gt;: Because the core Keycloak developers have largely been working for one customer (RedHat) and not the community at large, developers who are exploring Keycloak for the first time can find it hard to know where to ask question. While the Discourse, GitHub, Slack and mailing lists are a good direction, there’s not a definitive way to get support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI&lt;/strong&gt;: The Keycloak Admin UI, while complete, is intimidating to new users. Unlike the commercial alternatives, that have invested resources in building and measuring customer success into their UIs, while Keycloak’s attitude has been "&lt;a href="https://en.wikipedia.org/wiki/RTFM"&gt;RTFM&lt;/a&gt;". Furthermore, the user facing UIs of Keycloak are notoriously “rough edged”, commercial alternatives are beautiful, modern, and capable of easy customization and branding.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Obviously, we think that the barriers are something that can be solved, and &lt;a href="https://phasetwo.io"&gt;Phase Two&lt;/a&gt; has been working hard in its &lt;a href="https://github.com/p2-inc"&gt;open source extensions&lt;/a&gt; and &lt;a href="https://phasetwo.io/#pricing"&gt;cloud offerings&lt;/a&gt; to overcome these barriers. We've already made great strides, and believe that we're at the point where customers can realize the above advantages, while compromising relatively little -- All while achieving tremendous cost savings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Migrating from your current identity provider
&lt;/h3&gt;

&lt;p&gt;Already using one of the commercial systems? Keycloak is a complete, robust and mature identity solution that can replace your identity provider and user management systems &lt;strong&gt;today&lt;/strong&gt;. It has complete parity with all of the major features of commercial IAM systems, and because of reliance on standards, migration is easier than you think. By migrating to Keycloak, you gain full control over your authentication and authorization processes, enabling seamless integration, customization, and scalability tailored to your organization's unique needs. &lt;/p&gt;

&lt;p&gt;Phase two has implemented &lt;a href="https://phasetwo.io/docs/user-migration/"&gt;user migration&lt;/a&gt; support in the product for all tiers. This is meant to ease your transition from your existing user management system so that migration can occur incrementally with a complete fallback plan. For Premium and Enterprise subscribers, we include migration support. Contact &lt;a href="//mailto:sales@phasetwo.io"&gt;sales&lt;/a&gt; to get started with your migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In a landscape dominated by commercial IAM solutions, Keycloak shines as a compelling alternative that combines the power of open source with enterprise-grade features and flexibility. With its cost-effectiveness, customization capabilities, deployment flexibility, and active community support, Keycloak empowers organizations to take control of their identity infrastructure, unlock new possibilities, and adapt to evolving security and compliance requirements. Whether you're a startup looking to bootstrap your identity management or an enterprise seeking to streamline operations, Keycloak offers a compelling solution that puts you in the driver's seat of your IAM journey.&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>identityandaccessmanagement</category>
      <category>sso</category>
    </item>
    <item>
      <title>Securing Vue Apps with Keycloak</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Wed, 03 Apr 2024 02:26:39 +0000</pubDate>
      <link>https://dev.to/phasetwo/securing-vue-apps-with-keycloak-5a8f</link>
      <guid>https://dev.to/phasetwo/securing-vue-apps-with-keycloak-5a8f</guid>
      <description>&lt;p&gt;&lt;a href="https://vuejs.org/"&gt;Vue.js&lt;/a&gt; is an open source web framework that makes developing web applications easier.&lt;/p&gt;

&lt;p&gt;In this article we'll be using &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; to secure a Vue.js Web application. We're going to leverage &lt;a href="https://www.npmjs.com/package/oidc-client-ts"&gt;&lt;code&gt;oidc-client-ts&lt;/code&gt;&lt;/a&gt; to integrate OIDC authentication with the Vue app. The &lt;a href="https://www.npmjs.com/package/oidc-client-ts"&gt;&lt;code&gt;oidc-client-ts&lt;/code&gt;&lt;/a&gt; package is a well-maintained and used library. It provides a lot of utilities for building out a fully production app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
If you just want to skip to the code, visit the Phase Two &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/vue"&gt;Vue.js example&lt;/a&gt;. We are also building &lt;a href="https://github.com/p2-inc/examples"&gt;Keycloak examples&lt;/a&gt; for other frameworks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  TOC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keycloak Setup&lt;/li&gt;
&lt;li&gt;Vue.js + OIDC Client&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Setting up a Keycloak Instance &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;br&gt;
If you already have a functioning Keycloak instance, you can skip to the next section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;strong&gt;Keycloak Setup Details&lt;/strong&gt;
  &lt;br&gt;
Rather than trying to set up a "from scratch" instance of Keycloak, we're going to short-circuit that process by leveraging a Phase Two &lt;a href="https://phasetwo.io/"&gt;free Keycloak&lt;/a&gt; starter instance. The Starter provides a free hosted instance of Phase Two's enhanced Keycloak ready for light production use cases.

&lt;ul&gt;
&lt;li&gt;Visit the sign-up &lt;a href="https://phasetwo.io/dashboard/"&gt;page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter an email, use a Github account, or use an existing Google account to register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1jovhdjmmnys3kjp1wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1jovhdjmmnys3kjp1wb.png" alt="Register" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the register steps. This will include a sign-in link being sent to your email. Use that for password-less login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs73nhw4jl43li164nm5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs73nhw4jl43li164nm5i.png" alt="Email Link" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creating an account, a &lt;a href="https://www.youtube.com/watch?v=ZTFlc-3pG1M"&gt;realm&lt;/a&gt; is automatically created for you with all of the Phase Two enhancements. You need to create a Deployment in the Shared Phase Two infrastructure in order to gain access to the realm. Without a deployment created, the Create Shared Deployment modal will automatically pop up.&lt;/li&gt;
&lt;li&gt;Create a Shared Deployment by providing a region (pick something close to your existing infrastructure), a name for the deployment, and selecting the default organization that was created for you upon account creation. Hit "Confirm" when ready. Standby while our robots get to work generating your deployment. This can take a few seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oknshhzra67byi0uxoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7oknshhzra67byi0uxoz.png" alt="Create shared deployment" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the deployment is created and active, you can access the Keycloak Admin console by clicking "Open Console" for that deployment. Open it now to see the console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farwn5n54hbzwocobkmzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farwn5n54hbzwocobkmzs.png" alt="Deployments" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, move on to the next step in the tutorial. We'll be coming back to the Admin Console when its time to start connecting our App to the Keycloak instance.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up an OIDC Client
&lt;/h2&gt;

&lt;p&gt;We need to create a &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#con-oidc_server_administration_guide"&gt;OpenID Connect&lt;/a&gt; Client in Keycloak for the app to communicate with. &lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;Keycloak's &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients"&gt;docs&lt;/a&gt; provide steps for how to create an OIDC client and all the various configurations that can be introduced. Follow the steps below to create a client and get the right information necessary for app configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Create client&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Leave &lt;strong&gt;Client type&lt;/strong&gt; set to &lt;strong&gt;OpenID Connect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Enter a &lt;strong&gt;Client ID&lt;/strong&gt;. This ID is an alphanumeric string that is used in OIDC requests and in the Keycloak database to identify the client.&lt;/li&gt;
&lt;li&gt; Supply a &lt;strong&gt;Name&lt;/strong&gt; for the client.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vmlbu0gbf3wdmmacy23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vmlbu0gbf3wdmmacy23.png" alt="General settings" width="800" height="552"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Under the Capability Config section, leave the defaults as selected. This can be configured further later.&lt;/li&gt;
&lt;li&gt;Client authentication to Off.&lt;/li&gt;
&lt;li&gt;Authorization to Off.&lt;/li&gt;
&lt;li&gt;Standard flow checked. Direct access grants checked. All other items unchecked.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9fpa1jgny2300c6btd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9fpa1jgny2300c6btd.png" alt="Capbility config" width="800" height="551"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under Login settings we need to add a redirect URI and Web origin in order. Assuming you are using the example application:&lt;br&gt;
&lt;strong&gt;URI and Origin Details&lt;/strong&gt;&lt;br&gt;
The choice of &lt;code&gt;localhost&lt;/code&gt; is arbitrary. If you are using an example application running locally, this will apply. If you are using an app that you actually have deployed somewhere, then you will need to substitute the appropriate URI for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Valid redirect URI&lt;/em&gt; (allows redirect back to application)&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000/*
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;em&gt;Web origins&lt;/em&gt; (allows for Token auth call)&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk6j7sjbv2b5ns7jc85a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flk6j7sjbv2b5ns7jc85a.png" alt="Login settings" width="800" height="553"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  OIDC Config
&lt;/h3&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;We will need values to configure our application. To get these values follow the instructions below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt;Find the Client you just created and click on it. In the top right click the &lt;strong&gt;Action&lt;/strong&gt; dropdown and select &lt;strong&gt;Download adapter config&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Keycloak OIDC JSON&lt;/strong&gt; in the format option. The details section will populate with the details we will need.

&lt;ul&gt;
&lt;li&gt;Note the &lt;code&gt;realm&lt;/code&gt;, &lt;code&gt;auth-server-url&lt;/code&gt;, and &lt;code&gt;resource&lt;/code&gt; values.
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjxmpf25hhyogdno2yht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhjxmpf25hhyogdno2yht.png" alt="Adapter config" width="800" height="554"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Non-Admin User
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
It is bad practice to use your Admin user to sign in to an Application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we do not want to use our Admin user for signing into the app we will build, we need to add another non-admin user.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Users&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Add user&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Fill out the information for Email, First name, and Last name. Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; We will now set the password for this user manually. Click &lt;strong&gt;Credentials&lt;/strong&gt; (tab) and click &lt;strong&gt;Set Password&lt;/strong&gt;. Provide a password for this user. For our use case, as a tutorial, you can leave "Temporary" set to "Off".&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Save&lt;/strong&gt; and confirm the password by clicking &lt;strong&gt;Save password&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a Vue.js Project &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Clone the Phase Two &lt;a href="https://github.com/p2-inc/examples/"&gt;example repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Open the Vue &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/vue"&gt;folder&lt;/a&gt; within &lt;code&gt;/frameworks/vue&lt;/code&gt; and open the &lt;code&gt;/nuxt/oidc-client-ts&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; and then &lt;code&gt;npm run dev&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We'll review where we configure out Keycloak instance. First open &lt;code&gt;/auth.ts&lt;/code&gt;. In this file you will want to update it with the values for the Keycloak instance we set-up earlier in the tutorial. Update the &lt;code&gt;clientSecret&lt;/code&gt; with the value. Use and environment variable here if you wish.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;keycloakConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;authorityUrl:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://euc1.auth.ac"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;applicationUrl:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;realm:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shared-deployment-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;clientId:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reg-example-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;clientSecret:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CLIENT_SECRET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After the config, you can see how the OIDC instance is started.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;authority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;keycloakConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorityUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/auth/realms/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;keycloakConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;realm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;keycloakConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;client_secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;keycloakConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/auth`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;silent_redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/silent-refresh`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;post_logout_redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;response_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;userStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebStorageStateStore&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
     &lt;span class="na"&gt;loadUserInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;With the Keycloak instance defined, we attach this to the app instance for Vue. Switch to &lt;code&gt;/main.ts&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="c1"&gt;// ...&lt;/span&gt;
   &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;globalProperties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We pull in the &lt;code&gt;Auth&lt;/code&gt; instance then expose it through the &lt;code&gt;$auth&lt;/code&gt; variable.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;There are a few main pages in play here that we define to create paths the library can leverage. The &lt;code&gt;/view/auth&lt;/code&gt; and &lt;code&gt;/view/silent-refresh&lt;/code&gt; create paths at the same name. These are used to do the redirection during authentication. From within these we use the &lt;code&gt;Auth&lt;/code&gt; instance to direct the user around within the app. For instance in &lt;code&gt;/views/AuthView&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AuthAuthenticated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signinCallback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
         &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;router.push&lt;/code&gt; naively sends someone to the home page. This could be updated to go to any number of places, including the page one started the login flow from if you were to store that information to be retrieved.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now that we have all the things setup, we can define the user component &lt;code&gt;/components/User&lt;/code&gt; to easily pull information about the user's state and display the appropriate UI.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserComponent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signinRedirect&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
         &lt;span class="na"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signoutRedirect&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
       &lt;span class="p"&gt;};&lt;/span&gt;
     &lt;span class="p"&gt;},&lt;/span&gt;
     &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;created&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, the user object is now easily available. A simple &lt;code&gt;v-if="user"&lt;/code&gt; allows the app to determine what UI to show.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning more
&lt;/h2&gt;

&lt;p&gt;Phase Two's enhanced Keycloak provides many ways to quickly control and tweak the log in and user management experience. Our &lt;a href="https://phasetwo.io/blog"&gt;blog&lt;/a&gt; has many use cases from &lt;a href="https://phasetwo.io/blog/customizing-login-pages"&gt;customizing login pages&lt;/a&gt;, setting up &lt;a href="https://phasetwo.io/blog/set-up-magic-links"&gt;magic links&lt;/a&gt; (password-less sign in), and &lt;a href="https://phasetwo.io/product/organizations"&gt;Organization&lt;/a&gt; workflows.&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>sso</category>
      <category>vue</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Securing Nuxt Apps with Keycloak</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Mon, 11 Sep 2023 11:26:22 +0000</pubDate>
      <link>https://dev.to/phasetwo/securing-nuxt-apps-with-keycloak-28od</link>
      <guid>https://dev.to/phasetwo/securing-nuxt-apps-with-keycloak-28od</guid>
      <description>&lt;p&gt;&lt;a href="https://nuxt.com/"&gt;Nuxt&lt;/a&gt; is an open source web framework that makes developing web applications easier.&lt;/p&gt;

&lt;p&gt;In this article we'll be using &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; to secure a Nuxt Web application. We will use two different methods: &lt;a href="https://www.npmjs.com/package/keycloak-js"&gt;&lt;code&gt;keycloak-js&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/oidc-client-ts"&gt;&lt;code&gt;oidc-client-ts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
If you just want to skip to the code, visit the Phase Two &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/nuxt"&gt;Nuxt example&lt;/a&gt;. We are also building &lt;a href="https://github.com/p2-inc/examples"&gt;Keycloak examples&lt;/a&gt; for other frameworks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  TOC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keycloak Setup&lt;/li&gt;
&lt;li&gt;Nuxt + Keycloak-Js&lt;/li&gt;
&lt;li&gt;Nuxt + OIDC Client&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Setting up a Keycloak Instance &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;br&gt;
If you already have a functioning Keycloak instance, you can skip to the next section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;strong&gt;Keycloak Setup Details&lt;/strong&gt;
  &lt;br&gt;
Rather than trying to set up a "from scratch" instance of Keycloak, we're going to short-circuit that process by leveraging a Phase Two &lt;a href="https://phasetwo.io/"&gt;free Keycloak&lt;/a&gt; starter instance. The Starter provides a free hosted instance of Phase Two's enhanced Keycloak ready for light production use cases.

&lt;ul&gt;
&lt;li&gt;Visit the sign-up &lt;a href="https://phasetwo.io/dashboard/"&gt;page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter an email, use a Github account, or use an existing Google account to register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EPkJ6F5f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s1jovhdjmmnys3kjp1wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EPkJ6F5f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s1jovhdjmmnys3kjp1wb.png" alt="Register" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the register steps. This will include a sign-in link being sent to your email. Use that for password-less login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2xWa4hTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s73nhw4jl43li164nm5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2xWa4hTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s73nhw4jl43li164nm5i.png" alt="Email Link" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creating an account, a &lt;a href="https://www.youtube.com/watch?v=ZTFlc-3pG1M"&gt;realm&lt;/a&gt; is automatically created for you with all of the Phase Two enhancements. You need to create a Deployment in the Shared Phase Two infrastructure in order to gain access to the realm. Without a deployment created, the Create Shared Deployment modal will automatically pop up.&lt;/li&gt;
&lt;li&gt;Create a Shared Deployment by providing a region (pick something close to your existing infrastructure), a name for the deployment, and selecting the default organization that was created for you upon account creation. Hit "Confirm" when ready. Standby while our robots get to work generating your deployment. This can take a few seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7NJE_CUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oknshhzra67byi0uxoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7NJE_CUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oknshhzra67byi0uxoz.png" alt="Create shared deployment" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the deployment is created and active, you can access the Keycloak Admin console by clicking "Open Console" for that deployment. Open it now to see the console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qvcaZeL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arwn5n54hbzwocobkmzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qvcaZeL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arwn5n54hbzwocobkmzs.png" alt="Deployments" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, move on to the next step in the tutorial. We'll be coming back to the Admin Console when its time to start connecting our App to the Keycloak instance.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up an OIDC Client
&lt;/h2&gt;

&lt;p&gt;We need to create a &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#con-oidc_server_administration_guide"&gt;OpenID Connect&lt;/a&gt; Client in Keycloak for the app to communicate with. &lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;Keycloak's &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients"&gt;docs&lt;/a&gt; provide steps for how to create an OIDC client and all the various configurations that can be introduced. Follow the steps below to create a client and get the right information necessary for app configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Create client&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Leave &lt;strong&gt;Client type&lt;/strong&gt; set to &lt;strong&gt;OpenID Connect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Enter a &lt;strong&gt;Client ID&lt;/strong&gt;. This ID is an alphanumeric string that is used in OIDC requests and in the Keycloak database to identify the client.&lt;/li&gt;
&lt;li&gt; Supply a &lt;strong&gt;Name&lt;/strong&gt; for the client.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LxPTnMTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vmlbu0gbf3wdmmacy23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LxPTnMTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vmlbu0gbf3wdmmacy23.png" alt="General settings" width="800" height="553"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Under the Capability Config section, leave the defaults as selected. This can be configured further later.&lt;/li&gt;
&lt;li&gt;Client authentication to Off.&lt;/li&gt;
&lt;li&gt;Authorization to Off.&lt;/li&gt;
&lt;li&gt;Standard flow checked. Direct access grants checked. All other items unchecked.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kodtdcqS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rv9fpa1jgny2300c6btd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kodtdcqS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rv9fpa1jgny2300c6btd.png" alt="Capbility config" width="800" height="551"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under Login settings we need to add a redirect URI and Web origin in order. Assuming you are using the example application:&lt;br&gt;
&lt;strong&gt;URI and Origin Details&lt;/strong&gt;&lt;br&gt;
The choice of &lt;code&gt;localhost&lt;/code&gt; is arbitrary. If you are using an example application running locally, this will apply. If you are using an app that you actually have deployed somewhere, then you will need to substitute the appropriate URI for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Valid redirect URI&lt;/em&gt; (allows redirect back to application)&lt;br&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://localhost:3000/*
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;em&gt;Web origins&lt;/em&gt; (allows for Token auth call)&lt;br&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iaZxwNfL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lk6j7sjbv2b5ns7jc85a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iaZxwNfL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lk6j7sjbv2b5ns7jc85a.png" alt="Login settings" width="800" height="553"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  OIDC Config
&lt;/h3&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;We will need values to configure our application. To get these values follow the instructions below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt;Find the Client you just created and click on it. In the top right click the &lt;strong&gt;Action&lt;/strong&gt; dropdown and select &lt;strong&gt;Download adapter config&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Keycloak OIDC JSON&lt;/strong&gt; in the format option. The details section will populate with the details we will need.

&lt;ul&gt;
&lt;li&gt;Note the &lt;code&gt;realm&lt;/code&gt;, &lt;code&gt;auth-server-url&lt;/code&gt;, and &lt;code&gt;resource&lt;/code&gt; values.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jhZXQiwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjxmpf25hhyogdno2yht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jhZXQiwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjxmpf25hhyogdno2yht.png" alt="Adapter config" width="800" height="555"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Non-Admin User
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
It is bad practice to use your Admin user to sign in to an Application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we do not want to use our Admin user for signing into the app we will build, we need to add another non-admin user.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Users&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Add user&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Fill out the information for Email, First name, and Last name. Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; We will now set the password for this user manually. Click &lt;strong&gt;Credentials&lt;/strong&gt; (tab) and click &lt;strong&gt;Set Password&lt;/strong&gt;. Provide a password for this user. For our use case, as a tutorial, you can leave "Temporary" set to "Off".&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Save&lt;/strong&gt; and confirm the password by clicking &lt;strong&gt;Save password&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a Nuxt Project
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
We will use the Phase Two Nuxt example code here, but the logic could easily be applied to any existing application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This example uses Nuxt3. There are a couple methods by which you can integrate Keycloak to your Nuxt application. We're going to explore two methods here, one uses &lt;a href="https://www.npmjs.com/package/keycloak-js"&gt;&lt;code&gt;keycloak-js&lt;/code&gt;&lt;/a&gt; and the other leverages &lt;a href="https://www.npmjs.com/package/oidc-client-ts"&gt;&lt;code&gt;oidc-client-ts&lt;/code&gt;&lt;/a&gt;. The &lt;code&gt;keycloak-js&lt;/code&gt; library provides a simple, client-only method, but lacks some of the sophistication provided by the &lt;code&gt;oidc-client&lt;/code&gt; library that is heavily supported and more widely used.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using &lt;code&gt;keycloak-js&lt;/code&gt; &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
For this example, we need to disable "Client Authentication" in the OIDC client that was setup earlier. This is available under Client &amp;gt; Settings &amp;gt; Capability config &amp;gt; Client authentication to OFF.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Clone the Phase Two &lt;a href="https://github.com/p2-inc/examples/"&gt;example repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Open the Nuxt &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/nuxt"&gt;folder&lt;/a&gt; within &lt;code&gt;/frameworks/nuxt&lt;/code&gt; and open the &lt;code&gt;keycloak-js&lt;/code&gt; folder within &lt;code&gt;/frameworks/nuxt/keycloak-js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; and then &lt;code&gt;npm run dev&lt;/code&gt;. &lt;a href="https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter"&gt;&lt;code&gt;keycloak-js&lt;/code&gt;&lt;/a&gt; is a Javascript library that provides a fast way to secure an application.&lt;/li&gt;
&lt;li&gt;The project makes use of the following Nuxt items: components, composables, layouts, and plugins. We'll review each in kind.&lt;/li&gt;
&lt;li&gt;The main component that shows the User's authenticated state is in &lt;code&gt;/components/User&lt;/code&gt;. In this component we call the &lt;code&gt;useKeycloak&lt;/code&gt; composable, which let's us key into the &lt;code&gt;keycloak-js&lt;/code&gt; functions that we've wrapped to make easily availble.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;keycloak&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useKeycloak&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;keycloak&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;keycloak&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Lower in the file the component leverages &lt;code&gt;v-if&lt;/code&gt; checks to determine if the &lt;code&gt;authState&lt;/code&gt; is &lt;code&gt;authenticated&lt;/code&gt; or not. Depending on the state, a Log in or Log out button is available.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Let's take a look at the setup for the composable next. Our composable is in &lt;code&gt;/composables/keycloak-c&lt;/code&gt;. A composable is a function defined that can be called anywhere in the Nuxt application. It's a good way to abstract logic to be reused. In our case we use it to wrap a &lt;code&gt;keycloak-js&lt;/code&gt; plugin (more on that in the next step) and help provided a state value for the authenticated state.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useKeycloak&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nuxtApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useNuxtApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keycloak&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nuxtApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$keycloak&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Keycloak&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;authState&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unAuthenticated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

     &lt;span class="nx"&gt;keycloak&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onAuthSuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;authenticated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="nx"&gt;keycloak&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onAuthError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;keycloak&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;authState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;In the plugin, &lt;code&gt;/plugins/keycloak.client.ts&lt;/code&gt; we instantiate the &lt;code&gt;keycloak-js&lt;/code&gt; library. We can then attach that instance to the &lt;code&gt;NuxtApp&lt;/code&gt; instance. Substitute the correct values for your Keycloak instance that we created earlier in the tutorial.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineNuxtPlugin&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;nuxtApp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;initOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KeycloakConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://euc1.auth.ac/auth/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;realm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared-deployment-001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reg-example-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;};&lt;/span&gt;

     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keycloak&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Keycloak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

     &lt;span class="nx"&gt;nuxtApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$keycloak&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keycloak&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

     &lt;span class="nx"&gt;keycloak&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
       &lt;span class="na"&gt;onLoad&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;check-sso&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;The logic for checking the &lt;code&gt;authenticated&lt;/code&gt; state can be used to expand in ways to secure your site in a number of ways.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Using &lt;code&gt;oidc-client&lt;/code&gt; &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.npmjs.com/package/oidc-client-ts"&gt;&lt;code&gt;oidc-client-ts&lt;/code&gt;&lt;/a&gt; package is a well-maintained and used library. It provides a lot of utilities for building out a fully production app.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the Phase Two &lt;a href="https://github.com/p2-inc/examples/"&gt;example repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Open the Nuxt &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/nuxt"&gt;folder&lt;/a&gt; within &lt;code&gt;/frameworks/nuxt&lt;/code&gt; and open the &lt;code&gt;/nuxt/oidc-client-ts&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; and then &lt;code&gt;npm run dev&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The structure of the project is similar to the &lt;code&gt;keycloak-js&lt;/code&gt; version but with a the use of services, stores, and middleware.&lt;/li&gt;
&lt;li&gt;We'll review where we configure out Keycloak instance. First open &lt;code&gt;/services/keycloak-config.ts&lt;/code&gt;. In this file you will want to update it with the values for the Keycloak instance we set-up earlier in the tutorial. Make sure you are using the one with Client Authentication enabled. Update the &lt;code&gt;clientSecret&lt;/code&gt; with the value. Use and environment variable here if you wish.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;keycloakConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;authorityUrl:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://euc1.auth.ac"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;applicationUrl:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;realm:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shared-deployment-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;clientId:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reg-example-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;clientSecret:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CLIENT_SECRET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Switch over to the &lt;code&gt;/services/auth-service&lt;/code&gt; now to see how the Oidc instance is started. The class pulls in values from the &lt;code&gt;keycloakConfig&lt;/code&gt; to use in the constructor. The other functions are wrappers around methods provided by the &lt;code&gt;oidc-client&lt;/code&gt; library. This allows us to key into things like &lt;code&gt;signInRedirect&lt;/code&gt; and &lt;code&gt;signoutRedirect&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How the settings are integrated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;authority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;keycloakConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorityUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/auth/realms/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;keycloakConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;realm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;keycloakConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;client_secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;keycloakConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/auth`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;silent_redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/silent-refresh`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;post_logout_redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;response_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;userStore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebStorageStateStore&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
     &lt;span class="na"&gt;loadUserInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;UserManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example function wrapper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;signInRedirect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signinRedirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;With the &lt;code&gt;AuthService&lt;/code&gt; defined, we can now expose that through a composable. Switch to the &lt;code&gt;/composables/useServices&lt;/code&gt; file. The file is simple but provides a way for any component to hook into the service instance.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AuthService&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/services/auth-service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ApplicationService&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/services/application-service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/stores/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useServices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useAuth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
       &lt;span class="na"&gt;$application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ApplicationService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
     &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We pull in the &lt;code&gt;AuthService&lt;/code&gt; then expose it through the &lt;code&gt;$auth&lt;/code&gt; variable. The &lt;code&gt;$application&lt;/code&gt; variable exposes the &lt;code&gt;ApplicationService&lt;/code&gt; which is provided as an example of how you could secure API calls.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We leverage the &lt;a href="https://pinia.vuejs.org/"&gt;&lt;code&gt;pinia&lt;/code&gt;&lt;/a&gt; library to make store User information to make it easily accessible. Open &lt;code&gt;/stores/auth/index&lt;/code&gt;. From within this file, we can wrap the &lt;code&gt;User&lt;/code&gt; object exposed by the &lt;code&gt;oidc-client&lt;/code&gt; package. This can then be leveraged in the middleware function we want to define or to pull information quickly about the user.&lt;/li&gt;
&lt;li&gt;There are a few main pages in play here that we define to create paths the library can leverage. The &lt;code&gt;/pages/auth&lt;/code&gt;, &lt;code&gt;/pages/logout&lt;/code&gt;, &lt;code&gt;/pages/silent-refresh&lt;/code&gt; create paths at the same name. These are used to do the redirection during authentication or log out. From within these we use the &lt;code&gt;AuthService&lt;/code&gt; to direct the user around within the app. For instance in &lt;code&gt;/auth&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authenticateOidc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signInCallback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;

   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;authenticateOidc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;router.push&lt;/code&gt; naively sends someone to the home page. This could be updated to go to any number of places, including the page one started the login flow from if you were to store that information to be retrieved.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We have also created a middleware file in &lt;code&gt;/middleware/auth.global&lt;/code&gt; to be used in a couple of ways. It checks if the user is authenticated and based on that knowledge, stores the user information in the store (if not there) or could be used to send someone to login. For our example, we created buttons to initiate that but there is a comment which shows how you could force a set of paths to require login.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authFlowRoutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/silent-refresh&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/logout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineNuxtRouteMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useAuth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;services&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useServices&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;authFlowRoutes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;// use this to automatically force a sign in and redirect&lt;/span&gt;
       &lt;span class="c1"&gt;// services.$auth.signInRedirect();&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;authStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setUpUserCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Now that we have all the things setup, we can define the user component &lt;code&gt;/components/User&lt;/code&gt; to easily pull information about the user's state and display the appropriate UI.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useAuth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;authStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signInRedirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signOut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, the user object is now easily available. A simple &lt;code&gt;v-if="user"&lt;/code&gt; allows the app to determine what UI to show.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A bit more complicated of a setup, but more elegant in the handling of the logged in flow. The &lt;code&gt;oidc-client&lt;/code&gt; allows for much better fine-tuning of the experience.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Learning more
&lt;/h2&gt;

&lt;p&gt;Phase Two's enhanced Keycloak provides many ways to quickly control and tweak the log in and user management experience. Our &lt;a href="https://phasetwo.io/blog"&gt;blog&lt;/a&gt; has many use cases from &lt;a href="https://phasetwo.io/blog/customizing-login-pages"&gt;customizing login pages&lt;/a&gt;, setting up &lt;a href="https://phasetwo.io/blog/set-up-magic-links"&gt;magic links&lt;/a&gt; (password-less sign in), and &lt;a href="https://phasetwo.io/product/organizations"&gt;Organization&lt;/a&gt; workflows.&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>keycloak</category>
      <category>authentication</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Django Web Authentication with Keycloak</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Mon, 04 Sep 2023 14:50:13 +0000</pubDate>
      <link>https://dev.to/phasetwo/django-web-authentication-with-keycloak-3hl2</link>
      <guid>https://dev.to/phasetwo/django-web-authentication-with-keycloak-3hl2</guid>
      <description>&lt;p&gt;&lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt; is a high-level, open-source web framework for building web applications using the Python programming language. It follows the Model-View-Controller (MVC) architectural pattern.&lt;/p&gt;

&lt;p&gt;In this article we'll be using &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; to secure a Django Web application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
If you just want to skip to the code, visit the Phase Two &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/django"&gt;Django example&lt;/a&gt;. We are also building &lt;a href="https://github.com/p2-inc/examples"&gt;Keycloak examples&lt;/a&gt; for other frameworks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  TOC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Django Project Setup&lt;/li&gt;
&lt;li&gt;Keycloak Setup&lt;/li&gt;
&lt;li&gt;Django OIDC + Keycloak Integration&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Setting up a Django Project &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The following could be applied to an existing Django application, but we have chosen to use the excellent tutorial application built by &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django"&gt;Mozilla&lt;/a&gt; as our example. If you aren't yet familiar with Django, we encourage you to follow the tutorial there.&lt;/p&gt;

&lt;p&gt;The completed code for that tutorial is available in their GitHub repository. We'll clone it to get started.&lt;/p&gt;
&lt;h3&gt;
  
  
  Quick Start
&lt;/h3&gt;

&lt;p&gt;To get this project up and running locally on your computer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set up the &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/development_environment"&gt;Python development environment&lt;/a&gt;.
We recommend using a Python virtual environment.&lt;/li&gt;
&lt;li&gt;Assuming you have Python setup, run the following commands (if you're on Windows you may use &lt;code&gt;py&lt;/code&gt; or &lt;code&gt;py -3&lt;/code&gt; instead of &lt;code&gt;python&lt;/code&gt; to start Python):
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   pip install -r requirements.txt
   python manage.py makemigrations
   python manage.py migrate
   python manage.py collectstatic
   python manage.py test # Run the standard tests. These should all pass.
   python manage.py createsuperuser # Create a superuser
   python manage.py runserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Open a browser to &lt;code&gt;http://127.0.0.1:8000/admin/&lt;/code&gt; to open the admin site&lt;/li&gt;
&lt;li&gt;Create a few test objects of each type.&lt;/li&gt;
&lt;li&gt;Open tab to &lt;code&gt;http://127.0.0.1:8000&lt;/code&gt; to see the main site, with your new objects.&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Setting up a Keycloak Instance &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;br&gt;
If you already have a functioning Keycloak instance, you can skip to the next section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;strong&gt;Keycloak Setup Details&lt;/strong&gt;
  &lt;br&gt;
Rather than trying to set up a "from scratch" instance of Keycloak, we're going to short-circuit that process by leveraging a Phase Two &lt;a href="https://phasetwo.io/"&gt;free Keycloak&lt;/a&gt; starter instance. The Starter provides a free hosted instance of Phase Two's enhanced Keycloak ready for light production use cases.

&lt;ul&gt;
&lt;li&gt;Visit the sign-up &lt;a href="https://phasetwo.io/dashboard/"&gt;page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter an email, use a Github account, or use an existing Google account to register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EPkJ6F5f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s1jovhdjmmnys3kjp1wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EPkJ6F5f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s1jovhdjmmnys3kjp1wb.png" alt="Register" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the register steps. This will include a sign-in link being sent to your email. Use that for password-less login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2xWa4hTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s73nhw4jl43li164nm5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2xWa4hTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s73nhw4jl43li164nm5i.png" alt="Email Link" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creating an account, a &lt;a href="https://www.youtube.com/watch?v=ZTFlc-3pG1M"&gt;realm&lt;/a&gt; is automatically created for you with all of the Phase Two enhancements. You need to create a Deployment in the Shared Phase Two infrastructure in order to gain access to the realm. Without a deployment created, the Create Shared Deployment modal will automatically pop up.&lt;/li&gt;
&lt;li&gt;Create a Shared Deployment by providing a region (pick something close to your existing infrastructure), a name for the deployment, and selecting the default organization that was created for you upon account creation. Hit "Confirm" when ready. Standby while our robots get to work generating your deployment. This can take a few seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7NJE_CUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oknshhzra67byi0uxoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7NJE_CUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oknshhzra67byi0uxoz.png" alt="Create shared deployment" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the deployment is created and active, you can access the Keycloak Admin console by clicking "Open Console" for that deployment. Open it now to see the console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qvcaZeL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arwn5n54hbzwocobkmzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qvcaZeL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arwn5n54hbzwocobkmzs.png" alt="Deployments" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, move on to the next step in the tutorial. We'll be coming back to the Admin Console when its time to start connecting our App to the Keycloak instance.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up an OIDC Client
&lt;/h2&gt;

&lt;p&gt;We need to create a &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#con-oidc_server_administration_guide"&gt;OpenID Connect&lt;/a&gt; Client in Keycloak for the app to communicate with. &lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;Keycloak's &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients"&gt;docs&lt;/a&gt; provide steps for how to create an OIDC client and all the various configurations that can be introduced. Follow the steps below to create a client and get the right information necessary for app configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Create client&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Leave &lt;strong&gt;Client type&lt;/strong&gt; set to &lt;strong&gt;OpenID Connect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Enter a &lt;strong&gt;Client ID&lt;/strong&gt;. This ID is an alphanumeric string that is used in OIDC requests and in the Keycloak database to identify the client.&lt;/li&gt;
&lt;li&gt; Supply a &lt;strong&gt;Name&lt;/strong&gt; for the client.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LxPTnMTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vmlbu0gbf3wdmmacy23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LxPTnMTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vmlbu0gbf3wdmmacy23.png" alt="General settings" width="800" height="553"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Under the Capability Config section, leave the defaults as selected. This can be configured further later.&lt;/li&gt;
&lt;li&gt;Client authentication to On.&lt;/li&gt;
&lt;li&gt;Authorization to Off.&lt;/li&gt;
&lt;li&gt;Standard flow checked. Direct access grants checked. All other items unchecked.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pzbz3gkI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6qrgqmz8b4chnztrs8d8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pzbz3gkI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6qrgqmz8b4chnztrs8d8.png" alt="Capbility config" width="800" height="509"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under Login settings we need to add a redirect URI and Web origin in order. Assuming you are using the example application:&lt;br&gt;
&lt;strong&gt;URI and Origin Details&lt;/strong&gt;&lt;br&gt;
The choice of &lt;code&gt;localhost&lt;/code&gt; is arbitrary. If you are using an example application running locally, this will apply. If you are using an app that you actually have deployed somewhere, then you will need to substitute the appropriate URI for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Valid redirect URI&lt;/em&gt; (allows redirect back to application)&lt;br&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://localhost:3000/*
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;em&gt;Web origins&lt;/em&gt; (allows for Token auth call)&lt;br&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iaZxwNfL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lk6j7sjbv2b5ns7jc85a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iaZxwNfL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lk6j7sjbv2b5ns7jc85a.png" alt="Login settings" width="800" height="553"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  OIDC Config
&lt;/h3&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;br&gt;
We will need values to configure our application. To get these values follow the instructions below.

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt;Find the Client you just created and click on it. In the top right click the &lt;strong&gt;Action&lt;/strong&gt; dropdown and select &lt;strong&gt;Download adapter config&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Keycloak OIDC JSON&lt;/strong&gt; in the format option. The details section will populate with the details we will need.

&lt;ul&gt;
&lt;li&gt;Note the &lt;code&gt;realm&lt;/code&gt;, &lt;code&gt;auth-server-url&lt;/code&gt;, and &lt;code&gt;resource&lt;/code&gt; values.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jhZXQiwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjxmpf25hhyogdno2yht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jhZXQiwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjxmpf25hhyogdno2yht.png" alt="Adapter config" width="800" height="555"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You also need to copy the &lt;strong&gt;Client secret&lt;/strong&gt; in the &lt;strong&gt;Credential&lt;/strong&gt; tab for the client to use. Once on the Credential tab, click the copy button to copy the key to your clipboard. Save the key somewhere for use later in this tutorial
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_ZvyDdGz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/482rc92jw9h6ydmo8zvv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_ZvyDdGz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/482rc92jw9h6ydmo8zvv.png" alt="Copy Credential" width="800" height="507"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding a Non-Admin User
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
It is bad practice to use your Admin user to sign in to an Application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we do not want to use our Admin user for signing into the app we will build, we need to add another non-admin user.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Users&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Add user&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Fill out the information for Email, First name, and Last name. Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; We will now set the password for this user manually. Click &lt;strong&gt;Credentials&lt;/strong&gt; (tab) and click &lt;strong&gt;Set Password&lt;/strong&gt;. Provide a password for this user. For our use case, as a tutorial, you can leave "Temporary" set to "Off".&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Save&lt;/strong&gt; and confirm the password by clicking &lt;strong&gt;Save password&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;/p&gt;

&lt;h2&gt;
  
  
  Install and configure the Django OIDC library &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we've installed and configured Keycloak, we need to setup Django to replace the native authentication method provided by the framework. The first task is to install a library that is compatible with Keycloak's OIDC implementation.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://mozilla-django-oidc.readthedocs.io/"&gt;mozilla-django-oidc&lt;/a&gt; library provides an easy way to integrate Keycloak (or any OpenID Connect-compliant identity provider) with your Django app. It abstracts many of the complexities of integrating authentication and authorization. Here's how you can set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install the Package&lt;/strong&gt;:
Install the &lt;code&gt;mozilla-django-oidc&lt;/code&gt; package using pip:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   pip &lt;span class="nb"&gt;install &lt;/span&gt;mozilla-django-oidc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configure Django Settings&lt;/strong&gt;:
Update your Django app's &lt;code&gt;settings.py&lt;/code&gt; to include the necessary configurations for &lt;code&gt;mozilla-django-oidc&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
       &lt;span class="c1"&gt;# ...
&lt;/span&gt;       &lt;span class="s"&gt;'django.contrib.auth'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;'mozilla_django_oidc'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Load after django.contrib.auth
&lt;/span&gt;       &lt;span class="c1"&gt;# ...
&lt;/span&gt;   &lt;span class="p"&gt;]&lt;/span&gt;

   &lt;span class="n"&gt;AUTHENTICATION_BACKENDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="s"&gt;'mozilla_django_oidc.auth.OIDCAuthenticationBackend'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="c1"&gt;# ...
&lt;/span&gt;   &lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="n"&gt;OIDC_RP_CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your-client-id'&lt;/span&gt;
   &lt;span class="n"&gt;OIDC_RP_CLIENT_SECRET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'your-client-secret'&lt;/span&gt;
   &lt;span class="n"&gt;OIDC_OP_AUTHORIZATION_ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'https://keycloak-url/auth/realms/your-realm/protocol/openid-connect/auth'&lt;/span&gt;
   &lt;span class="n"&gt;OIDC_OP_TOKEN_ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'https://keycloak-url/auth/realms/your-realm/protocol/openid-connect/token'&lt;/span&gt;
   &lt;span class="n"&gt;OIDC_OP_USER_ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'https://keycloak-url/auth/realms/your-realm/protocol/openid-connect/userinfo'&lt;/span&gt;
   &lt;span class="n"&gt;OIDC_OP_JWKS_ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'https://keycloak-url/auth/realms/your-realm/protocol/openid-connect/certs'&lt;/span&gt;
   &lt;span class="n"&gt;OIDC_RP_SIGN_ALGO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'RS256'&lt;/span&gt;

   &lt;span class="n"&gt;LOGIN_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'oidc_authentication_init'&lt;/span&gt;
   &lt;span class="n"&gt;LOGOUT_REDIRECT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'/'&lt;/span&gt;
   &lt;span class="n"&gt;LOGIN_REDIRECT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'/'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Replace &lt;code&gt;your-client-id&lt;/code&gt;, &lt;code&gt;your-client-secret&lt;/code&gt;, and the Keycloak URLs with your actual Keycloak configurations.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add URLs&lt;/strong&gt;:
Update your Django app's &lt;code&gt;urls.py&lt;/code&gt; to include the authentication URLs provided by &lt;code&gt;mozilla-django-oidc&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
       &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'oidc/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'mozilla_django_oidc.urls'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
   &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Using it in your app
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Protect your views
&lt;/h3&gt;

&lt;p&gt;Use Decorators for Access Control. You can now use the &lt;code&gt;@oidc_protected&lt;/code&gt; decorator to protect views that require authentication and potentially specific roles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mozilla_django_oidc.decorators&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;oidc_protected&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;oidc_protected&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;protected_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Your view logic
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Accessing user information
&lt;/h3&gt;

&lt;p&gt;You can access user information after authentication using the &lt;code&gt;request.oidc_user&lt;/code&gt; attribute. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;profile_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;user_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oidc_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userinfo&lt;/span&gt;
    &lt;span class="c1"&gt;# Access user_info['sub'], user_info['email'], etc.
&lt;/span&gt;    &lt;span class="c1"&gt;# Your view logic
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, &lt;code&gt;mozilla-django-oidc&lt;/code&gt; looks up a Django user matching the email field to the email address returned in the user info data from Keycloak.&lt;/p&gt;

&lt;p&gt;If a user logs into your site and doesn’t already have an account, by default, &lt;code&gt;mozilla-django-oidc&lt;/code&gt; will create a new Django user account. It will create the User instance filling in the username (hash of the email address) and email fields.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use Username rather than Email
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;mozilla-django-oidc&lt;/code&gt; defaults to setting up Django users using the email address as the user name from keycloak was required. Fortunately, &lt;code&gt;preferred_username&lt;/code&gt; is set up by default in Keycloak as a claim. The claim can used by overriding the &lt;code&gt;OIDCAuthenticationBackend&lt;/code&gt; class in &lt;code&gt;mozilla_django_oidc.auth&lt;/code&gt; and referring to this in &lt;code&gt;AUTHENTICATION_BACKENDS&lt;/code&gt; as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# Classes to override default OIDCAuthenticationBackend (Keycloak authentication)
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mozilla_django_oidc.auth&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OIDCAuthenticationBackend&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KeycloakOIDCAuthenticationBackend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OIDCAuthenticationBackend&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
     &lt;span class="s"&gt;""" Overrides Authentication Backend so that Django users are
         created with the keycloak preferred_username.
         If nothing found matching the email, then try the username.
     """&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KeycloakOIDCAuthenticationBackend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'given_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'family_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'preferred_username'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filter_users_by_claims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
     &lt;span class="s"&gt;""" Return all users matching the specified email.
         If nothing found matching the email, then try the username
     """&lt;/span&gt;
     &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;preferred_username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'preferred_username'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email__iexact&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;preferred_username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
             &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
         &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username__iexact&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;preferred_username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'given_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'family_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'preferred_username'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In settings.py, overide the new library you have just added in AUTHENTICATION_BACKENDS :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt; &lt;span class="c1"&gt;# mozilla_django_oidc - Keycloak authentication
&lt;/span&gt; &lt;span class="s"&gt;"fragalysis.auth.KeycloakOIDCAuthenticationBackend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Logging out
&lt;/h3&gt;

&lt;p&gt;You can use the &lt;code&gt;@oidc_logout&lt;/code&gt; decorator to log the user out of both your app and Keycloak:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mozilla_django_oidc.decorators&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;oidc_logout&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;oidc_logout&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;logout_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Your logout view logic
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add support for Django Rest Framework
&lt;/h2&gt;

&lt;p&gt;Django Rest Framework (DRF) is a flexible toolkit built on top of Django, specifically designed for building RESTful APIs.&lt;/p&gt;

&lt;p&gt;If you want DRF to authenticate users based on an OAuth access token provided in the Authorization header, you can use the DRF-specific authentication class which ships with the package.&lt;/p&gt;

&lt;p&gt;Add this to your settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;REST_FRAMEWORK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'DEFAULT_AUTHENTICATION_CLASSES'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s"&gt;'mozilla_django_oidc.contrib.drf.OIDCAuthentication'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'rest_framework.authentication.SessionAuthentication'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;# other authentication classes, if needed
&lt;/span&gt;    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this only takes care of authenticating against an access token, and provides no options to create or renew tokens.&lt;/p&gt;

&lt;p&gt;If you’ve created a custom Django OIDCAuthenticationBackend and added that to your AUTHENTICATION_BACKENDS, the DRF class should be smart enough to figure that out. Alternatively, you can manually set the OIDC backend to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;OIDC_DRF_AUTH_BACKEND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'mozilla_django_oidc.auth.OIDCAuthenticationBackend'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Learning more
&lt;/h2&gt;

&lt;p&gt;Phase Two's enhanced Keycloak provides many ways to quickly control and tweak the log in and user management experience. Our &lt;a href="https://phasetwo.io/blog"&gt;blog&lt;/a&gt; has many use cases from &lt;a href="https://phasetwo.io/blog/customizing-login-pages"&gt;customizing login pages&lt;/a&gt;, setting up &lt;a href="https://phasetwo.io/blog/set-up-magic-links"&gt;magic links&lt;/a&gt; (password-less sign in), and &lt;a href="https://phasetwo.io/product/organizations"&gt;Organization&lt;/a&gt; workflows.&lt;/p&gt;

</description>
      <category>django</category>
      <category>keycloak</category>
      <category>authentication</category>
      <category>sso</category>
    </item>
    <item>
      <title>Securing a Next.js Application with Keycloak</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Wed, 16 Aug 2023 03:28:27 +0000</pubDate>
      <link>https://dev.to/phasetwo/securing-a-nextjs-application-with-keycloak-gm3</link>
      <guid>https://dev.to/phasetwo/securing-a-nextjs-application-with-keycloak-gm3</guid>
      <description>&lt;p&gt;In this article, we'll be using &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; to quickly augment an application with user management and SSO. We will demonstrate the integration by securing a page for logged-in users. This quickly provides a jump-off point to more complex integrations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
If you just want to skip to the code, visit the Phase Two &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/nextjs"&gt;Next.js example&lt;/a&gt;. We also have a plain &lt;a href="https://phasetwo.io/blog/https://phasetwo.io/blog/instant-user-managemenet-and-sso-for-reactjs"&gt;React example&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  TOC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keycloak Setup&lt;/li&gt;
&lt;li&gt;Next.js + Keycloak Integration&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Setting up a Keycloak Instance &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;br&gt;
If you already have a functioning Keycloak instance, you can skip to the next section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;strong&gt;Keycloak Setup Details&lt;/strong&gt;
  &lt;br&gt;
Rather than trying to set up a "from scratch" instance of Keycloak, we're going to short-circuit that process by leveraging a Phase Two &lt;a href="https://phasetwo.io/"&gt;free Keycloak&lt;/a&gt; starter instance. The Starter provides a free hosted instance of Phase Two's enhanced Keycloak ready for light production use cases.

&lt;ul&gt;
&lt;li&gt;Visit the sign-up &lt;a href="https://phasetwo.io/dashboard/"&gt;page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter an email, use a Github account, or use an existing Google account to register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EPkJ6F5f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s1jovhdjmmnys3kjp1wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EPkJ6F5f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s1jovhdjmmnys3kjp1wb.png" alt="Register" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the register steps. This will include a sign-in link being sent to your email. Use that for password-less login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2xWa4hTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s73nhw4jl43li164nm5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2xWa4hTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s73nhw4jl43li164nm5i.png" alt="Email Link" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creating an account, a &lt;a href="https://www.youtube.com/watch?v=ZTFlc-3pG1M"&gt;realm&lt;/a&gt; is automatically created for you with all of the Phase Two enhancements. You need to create a Deployment in the Shared Phase Two infrastructure in order to gain access to the realm. Without a deployment created, the Create Shared Deployment modal will automatically pop up.&lt;/li&gt;
&lt;li&gt;Create a Shared Deployment by providing a region (pick something close to your existing infrastructure), a name for the deployment, and selecting the default organization that was created for you upon account creation. Hit "Confirm" when ready. Standby while our robots get to work generating your deployment. This can take a few seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7NJE_CUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oknshhzra67byi0uxoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7NJE_CUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oknshhzra67byi0uxoz.png" alt="Create shared deployment" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the deployment is created and active, you can access the Keycloak Admin console by clicking "Open Console" for that deployment. Open it now to see the console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qvcaZeL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arwn5n54hbzwocobkmzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qvcaZeL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arwn5n54hbzwocobkmzs.png" alt="Deployments" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, move on to the next step in the tutorial. We'll be coming back to the Admin Console when its time to start connecting our App to the Keycloak instance.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up an OIDC Client
&lt;/h2&gt;

&lt;p&gt;We need to create a &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#con-oidc_server_administration_guide"&gt;OpenID Connect&lt;/a&gt; Client in Keycloak for the app to communicate with. &lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;Keycloak's &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients"&gt;docs&lt;/a&gt; provide steps for how to create an OIDC client and all the various configurations that can be introduced. Follow the steps below to create a client and get the right information necessary for app configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Create client&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Leave &lt;strong&gt;Client type&lt;/strong&gt; set to &lt;strong&gt;OpenID Connect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Enter a &lt;strong&gt;Client ID&lt;/strong&gt;. This ID is an alphanumeric string that is used in OIDC requests and in the Keycloak database to identify the client.&lt;/li&gt;
&lt;li&gt; Supply a &lt;strong&gt;Name&lt;/strong&gt; for the client.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LxPTnMTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vmlbu0gbf3wdmmacy23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LxPTnMTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vmlbu0gbf3wdmmacy23.png" alt="General settings" width="800" height="553"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Under the Capability Config section, leave the defaults as selected. This can be configured further later.&lt;/li&gt;
&lt;li&gt;Client authentication to On.&lt;/li&gt;
&lt;li&gt;Authorization to Off.&lt;/li&gt;
&lt;li&gt;Standard flow checked. Direct access grants checked. All other items unchecked.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pzbz3gkI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6qrgqmz8b4chnztrs8d8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pzbz3gkI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6qrgqmz8b4chnztrs8d8.png" alt="Capbility config" width="800" height="509"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under Login settings we need to add a redirect URI and Web origin in order. Assuming you are using the example application:&lt;br&gt;
&lt;strong&gt;URI and Origin Details&lt;/strong&gt;&lt;br&gt;
The choice of &lt;code&gt;localhost&lt;/code&gt; is arbitrary. If you are using an example application running locally, this will apply. If you are using an app that you actually have deployed somewhere, then you will need to substitute the appropriate URI for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Valid redirect URI&lt;/em&gt; (allows redirect back to application)&lt;br&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://localhost:3000/*
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;em&gt;Web origins&lt;/em&gt; (allows for Token auth call)&lt;br&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iaZxwNfL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lk6j7sjbv2b5ns7jc85a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iaZxwNfL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lk6j7sjbv2b5ns7jc85a.png" alt="Login settings" width="800" height="553"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  OIDC Config
&lt;/h3&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;br&gt;
We will need values to configure our application. To get these values follow the instructions below.

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt;Find the Client you just created and click on it. In the top right click the &lt;strong&gt;Action&lt;/strong&gt; dropdown and select &lt;strong&gt;Download adapter config&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Keycloak OIDC JSON&lt;/strong&gt; in the format option. The details section will populate with the details we will need.

&lt;ul&gt;
&lt;li&gt;Note the &lt;code&gt;realm&lt;/code&gt;, &lt;code&gt;auth-server-url&lt;/code&gt;, and &lt;code&gt;resource&lt;/code&gt; values.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jhZXQiwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjxmpf25hhyogdno2yht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jhZXQiwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjxmpf25hhyogdno2yht.png" alt="Adapter config" width="800" height="555"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You also need to copy the &lt;strong&gt;Client secret&lt;/strong&gt; in the &lt;strong&gt;Credential&lt;/strong&gt; tab for the client to use. Once on the Credential tab, click the copy button to copy the key to your clipboard. Save the key somewhere for use later in this tutorial
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_ZvyDdGz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/482rc92jw9h6ydmo8zvv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_ZvyDdGz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/482rc92jw9h6ydmo8zvv.png" alt="Copy Credential" width="800" height="507"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding a Non-Admin User
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
It is bad practice to use your Admin user to sign in to an Application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we do not want to use our Admin user for signing into the app we will build, we need to add another non-admin user.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Users&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Add user&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Fill out the information for Email, First name, and Last name. Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; We will now set the password for this user manually. Click &lt;strong&gt;Credentials&lt;/strong&gt; (tab) and click &lt;strong&gt;Set Password&lt;/strong&gt;. Provide a password for this user. For our use case, as a tutorial, you can leave "Temporary" set to "Off".&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Save&lt;/strong&gt; and confirm the password by clicking &lt;strong&gt;Save password&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a Next.js Project &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
We will use the Phase Two Next.js example code here, but the logic could easily be applied to any existing application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This example uses Next.js 13 and splits &lt;code&gt;server&lt;/code&gt; and &lt;code&gt;client&lt;/code&gt; components accordingly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the Phase Two &lt;a href="https://github.com/p2-inc/examples/"&gt;example repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Open the Next.js &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/nextjs"&gt;folder&lt;/a&gt; within &lt;code&gt;/frameworks/nextjs&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; and then &lt;code&gt;npm run dev&lt;/code&gt;. This example leverages &lt;a href="https://next-auth.js.org/"&gt;NextAuth.js&lt;/a&gt; to provide hook and HOC support.&lt;/li&gt;
&lt;li&gt;NextAuth.js configures an API route that is uses for the Authentication of the Client. It generates the routes automatically for you. These are added to Next.js in the &lt;code&gt;api/auth/[...nextauth]/route.ts&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Open the &lt;code&gt;src/lib/auth.ts&lt;/code&gt; file. This is a server only file. We will be updating a few values from the prior section where we set up our OIDC client. Taking the values from the OIDC Client Config section, set those values in the code. While it is recommended to use Environment variables for the secret, for the purpose of this tutorial, paste in the &lt;strong&gt;Client secret&lt;/strong&gt; from the OIDC client creation section for the value of &lt;code&gt;clientSecret&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authServerUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://euc1.auth.ac/auth/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;realm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared-deployment-001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reg-example-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CLIENT_SECRET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Paste "Client secret" here. Use Environment variables in prod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Those are used to popluate the &lt;code&gt;AuthOptions&lt;/code&gt; config for the &lt;code&gt;KeycloakProvider&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AuthOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextAuthOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;KeycloakProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;authServerUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;realms/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;realm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The config is then provided to the &lt;code&gt;AuthProvider&lt;/code&gt; in the &lt;code&gt;/src/app/layout.tsx&lt;/code&gt; file. Next.js uses this file to generate an HTML view for this page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextAuthProvider&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;AuthProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./providers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuthProvider&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;oidcConfig&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/AuthProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, our entire application will be able to access all information and methods needed to perform authentication. View the &lt;code&gt;providers.tsx&lt;/code&gt; file for additional information about how the &lt;code&gt;SessionProvider&lt;/code&gt; is used. The &lt;code&gt;SessionProvider&lt;/code&gt; enables use of Hooks to derive the authenticated state. View &lt;code&gt;user.component.tsx&lt;/code&gt; for exactly how the code is authenticating your user. The sections rendering the "Log in" and "Log out" buttons are conditional areas based on the authenticated context. The buttons invoke functions provided by NextAuth.&lt;/p&gt;

&lt;p&gt;The logic using the hook to conditionally determine the Authenticated state, can be used to secure routes, components, and more.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="http://localhost:3000"&gt;localhost:3000&lt;/a&gt;. You will see the Phase Two example landing page. You current state should be "Not authenticated". Click &lt;strong&gt;Log In&lt;/strong&gt;. This will redirect you to your login page.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
Use the non-admin user created in the previous section to sign in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Enter the credentials of the non-admin user you created. Click &lt;strong&gt;Submit&lt;/strong&gt;. You will then be redirected to the application. The Phase Two example landing page now loads your "Authenticated" state, displaying your user's email and their Token.&lt;/li&gt;
&lt;li&gt;After your first log in, click &lt;strong&gt;Log out&lt;/strong&gt;. Then click &lt;strong&gt;Log in&lt;/strong&gt; again. Notice how this time you will not be redirected to sign in as your state is already in the browser. Neat! If you clear the browser state for that tab, then you will have to be redirected away to sign-in again.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Learning more
&lt;/h2&gt;

&lt;p&gt;Phase Two's enhanced Keycloak provides many ways to quickly control and tweak the log in and user management experience. Our &lt;a href="https://phasetwo.io/blog"&gt;blog&lt;/a&gt; has many use cases from &lt;a href="https://phasetwo.io/blog/customizing-login-pages"&gt;customizing login pages&lt;/a&gt;, setting up &lt;a href="https://phasetwo.io/blog/set-up-magic-links"&gt;magic links&lt;/a&gt; (password-less sign in), and &lt;a href="https://phasetwo.io/product/organizations"&gt;Organization&lt;/a&gt; workflows.&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>authentication</category>
      <category>sso</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Instant User Management, SSO, and Secure Pages for ReactJS with Keycloak</title>
      <dc:creator>pnzrr</dc:creator>
      <pubDate>Wed, 02 Aug 2023 16:05:43 +0000</pubDate>
      <link>https://dev.to/phasetwo/instant-user-management-sso-and-secure-pages-for-reactjs-with-keycloak-4hej</link>
      <guid>https://dev.to/phasetwo/instant-user-management-sso-and-secure-pages-for-reactjs-with-keycloak-4hej</guid>
      <description>&lt;p&gt;In this article, we'll be using &lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; to quickly augment an application with user management and SSO. We will demonstrate the integration by securing a page for logged-in users. This quickly provides a jump-off point to more complex integrations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phasetwo.io/" class="ltag_cta ltag_cta--branded"&gt;Phase Two&lt;/a&gt;
 is a &lt;a href="https://phasetwo.io/"&gt;Keycloak as a Service&lt;/a&gt; provider enabling SaaS builders to accelerate time-to-market with powerful enterprise features like SSO, identity, and user management features. Phase Two enhances Keycloak through a variety of open-source extentions for modern SaaS use cases. Phase Two supports both hosted and on-premise deployment options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is Keycloak?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.keycloak.org/"&gt;Keycloak&lt;/a&gt; has been a leader in the Identity and Access Management world since its launch almost 8 years ago. It is an open-source offering under the stewardship of &lt;a href="https://www.redhat.com/"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
If you just want to skip to the code, visit the Phase Two &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/reactjs"&gt;ReactJS example&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  TOC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Keycloak Setup&lt;/li&gt;
&lt;li&gt;ReactJS + Keycloak Integration&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Setting up a Keycloak Instance
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP&lt;/strong&gt;&lt;br&gt;
If you already have a functioning Keycloak instance, you can skip to the next section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;Rather than trying to set up a "from scratch" instance of Keycloak, we're going to short-circuit that process by leveraging a Phase Two &lt;a href="https://phasetwo.io/"&gt;free Keycloak&lt;/a&gt; starter instance. The Starter provides a free hosted instance of Phase Two's enhanced Keycloak ready for light production use cases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visit the sign-up &lt;a href="https://phasetwo.io/dashboard/"&gt;page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter an email, use a Github account, or use an existing Google account to register.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EPkJ6F5f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s1jovhdjmmnys3kjp1wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EPkJ6F5f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s1jovhdjmmnys3kjp1wb.png" alt="Register" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the register steps. This will include a sign-in link being sent to your email. Use that for password-less login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2xWa4hTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s73nhw4jl43li164nm5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2xWa4hTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s73nhw4jl43li164nm5i.png" alt="Email Link" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After creating an account, a &lt;a href="https://www.youtube.com/watch?v=ZTFlc-3pG1M"&gt;realm&lt;/a&gt; is automatically created for you with all of the Phase Two enhancements. You need to create a Deployment in the Shared Phase Two infrastructure in order to gain access to the realm. Without a deployment created, the Create Shared Deployment modal will automatically pop up.&lt;/li&gt;
&lt;li&gt;Create a Shared Deployment by providing a region (pick something close to your existing infrastructure), a name for the deployment, and selecting the default organization that was created for you upon account creation. Hit "Confirm" when ready. Standby while our robots get to work generating your deployment. This can take a few seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7NJE_CUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oknshhzra67byi0uxoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7NJE_CUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oknshhzra67byi0uxoz.png" alt="Create shared deployment" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the deployment is created and active, you can access the Keycloak Admin console by clicking "Open Console" for that deployment. Open it now to see the console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qvcaZeL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arwn5n54hbzwocobkmzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qvcaZeL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/arwn5n54hbzwocobkmzs.png" alt="Deployments" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, move on to the next step in the tutorial. We'll be coming back to the Admin Console when its time to start connecting our App to the Keycloak instance.&lt;/p&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up an OIDC Client
&lt;/h2&gt;

&lt;p&gt;We need to create a &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#con-oidc_server_administration_guide"&gt;OpenID Connect&lt;/a&gt; Client in Keycloak for the app to communicate with. &lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;Keycloak's &lt;a href="https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients"&gt;docs&lt;/a&gt; provide steps for how to create an OIDC client and all the various configurations that can be introduced. Follow the steps below to create a client and get the right information necessary for app configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Create client&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Leave &lt;strong&gt;Client type&lt;/strong&gt; set to &lt;strong&gt;OpenID Connect&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Enter a &lt;strong&gt;Client ID&lt;/strong&gt;. This ID is an alphanumeric string that is used in OIDC requests and in the Keycloak database to identify the client.&lt;/li&gt;
&lt;li&gt; Supply a &lt;strong&gt;Name&lt;/strong&gt; for the client.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LxPTnMTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vmlbu0gbf3wdmmacy23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LxPTnMTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vmlbu0gbf3wdmmacy23.png" alt="General settings" width="800" height="553"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Under the Capability Config section, leave the defaults as selected. This can be configured further later.&lt;/li&gt;
&lt;li&gt;Client authentication to Off.&lt;/li&gt;
&lt;li&gt;Authorization to Off.&lt;/li&gt;
&lt;li&gt;Standard flow checked. Direct access grants checked. All other items unchecked.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Next&lt;/strong&gt;.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kodtdcqS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rv9fpa1jgny2300c6btd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kodtdcqS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rv9fpa1jgny2300c6btd.png" alt="Capbility config" width="800" height="551"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under Login settings we need to add a redirect URI and Web origin in order. Assuming you are using the example application:&lt;br&gt;
&lt;strong&gt;URI and Origin Details&lt;/strong&gt;&lt;br&gt;
The choice of &lt;code&gt;localhost&lt;/code&gt; is arbitrary. If you are using an example application running locally, this will apply. If you are using an app that you actually have deployed somewhere, then you will need to substitute the appropriate URI for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Valid redirect URI&lt;/em&gt; (allows redirect back to application)&lt;br&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://localhost:3000/*
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;em&gt;Web origins&lt;/em&gt; (allows for Token auth call)&lt;br&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iaZxwNfL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lk6j7sjbv2b5ns7jc85a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iaZxwNfL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lk6j7sjbv2b5ns7jc85a.png" alt="Login settings" width="800" height="553"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  OIDC Config
&lt;/h3&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;p&gt;We will need values to configure our application. To get these values follow the instructions below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Clients&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt;Find the Client you just created and click on it. In the top right click the &lt;strong&gt;Action&lt;/strong&gt; dropdown and select &lt;strong&gt;Download adapter config&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Keycloak OIDC JSON&lt;/strong&gt; in the format option. The details section will populate with the details we will need.

&lt;ul&gt;
&lt;li&gt;Note the &lt;code&gt;realm&lt;/code&gt;, &lt;code&gt;auth-server-url&lt;/code&gt;, and &lt;code&gt;resource&lt;/code&gt; values.
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jhZXQiwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjxmpf25hhyogdno2yht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jhZXQiwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjxmpf25hhyogdno2yht.png" alt="Adapter config" width="800" height="555"&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Non-Admin User
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
It is bad practice to use your Admin user to sign in to an Application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we do not want to use our Admin user for signing into the app we will build, we need to add a another non-admin user.&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Details&lt;/strong&gt;
  &lt;ol&gt;
&lt;li&gt; Open the Admin UI by clicking &lt;strong&gt;Open Console&lt;/strong&gt; in the Phase Two Dashboard.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Users&lt;/strong&gt; in the menu.&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Add user&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; Fill out the information for Email, First name, and Last name. Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt; We will now set the password for this user manually. Click &lt;strong&gt;Credentials&lt;/strong&gt; (tab) and click &lt;strong&gt;Set Password&lt;/strong&gt;. Provide a password for this user. For our use case, as a tutorial, you can leave "Temporary" set to "Off".&lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Save&lt;/strong&gt; and confirm the password by clicking &lt;strong&gt;Save password&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a ReactJS Project &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
We will use the Phase Two ReactJS example code here, but the logic could easily be applied to any existing application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Clone the Phase Two &lt;a href="https://github.com/p2-inc/examples/"&gt;example repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Open the ReactJS &lt;a href="https://github.com/p2-inc/examples/tree/main/frameworks/reactjs"&gt;folder&lt;/a&gt; within &lt;code&gt;/frameworks/reactjs&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; and then &lt;code&gt;npm start&lt;/code&gt;. This example leverages &lt;a href="https://github.com/authts/react-oidc-context/tree/f175dcba6ab09871b027d6a2f2224a17712b67c5"&gt;react-oidc-context&lt;/a&gt; (which uses &lt;a href="https://github.com/authts/oidc-client-ts"&gt;oidc-client-ts&lt;/a&gt;) to provide hook and HOC support.&lt;/li&gt;
&lt;li&gt;Open the &lt;code&gt;index.tsx&lt;/code&gt; file. We will be updating a few values from the prior section where we set up our OIDC client. Taking the values from the OIDC Client Config section, set those values in the code.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authServerUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://euc1.auth.ac/auth/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;realm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;shared-deployment-001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reg-example-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are used to popluate the OIDC config&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oidcConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;authority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;authServerUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;realms/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;realm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000/authenticated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;onSigninCallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
       &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replaceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="p"&gt;{},&lt;/span&gt;
         &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;
       &lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The config is then provided to the &lt;code&gt;AuthProvider&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuthProvider&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;oidcConfig&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/AuthProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point our entire applicationw will be able to access all information and methods needed to perform authentication. View &lt;code&gt;Auth.tsx&lt;/code&gt; for exactly how the code is authenticating your user. The sections rendering the "Log in" and "Log out" buttons are conditional areas based on the authenticated context.&lt;/p&gt;

&lt;p&gt;This login of using the hook to conditionally determine the Authenticated state, can be used to secure routes, components, and more.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open &lt;a href="http://localhost:3000"&gt;localhost:3000&lt;/a&gt;. You will see the Phase Two example landing page. You current state should be "Not authenticated". Click &lt;strong&gt;Log In&lt;/strong&gt;. This will redirect you to your login page.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;br&gt;
Use the non-admin user created in the previous section to sign in.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter the credentials of the non-admin user you created. Click &lt;strong&gt;Submit&lt;/strong&gt;. You will then be redirected to the application. The Phase Two example landing page now loads your "Authenticated" state, displaying your user's email and their Token.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After your first log in, click &lt;strong&gt;Log out&lt;/strong&gt;. Then click &lt;strong&gt;Log in&lt;/strong&gt; again. Notice how this time you will not be redirected to sign in as your state is already in the browser. Neat! If you clear the browser state for that tab, then you will have to be redirected away to sign-in again.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Learning more
&lt;/h2&gt;

&lt;p&gt;Phase Two's enhanced Keycloak provides many ways to quickly control and tweak the log in and user management experience. Our &lt;a href="https://phasetwo.io/blog"&gt;blog&lt;/a&gt; has many use cases from &lt;a href="https://phasetwo.io/blog/customizing-login-pages"&gt;customizing login pages&lt;/a&gt;, setting up &lt;a href="https://phasetwo.io/blog/set-up-magic-links"&gt;magic links&lt;/a&gt; (password-less sign in), and &lt;a href="https://phasetwo.io/product/organizations"&gt;Organization&lt;/a&gt; workflows.&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>authentication</category>
      <category>sso</category>
      <category>react</category>
    </item>
  </channel>
</rss>
