<?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>Forem: Alisa</title>
    <description>The latest articles on Forem by Alisa (@alisaduncan).</description>
    <link>https://forem.com/alisaduncan</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%2Fuser%2Fprofile_image%2F10521%2Fbb518cd1-0284-4059-bde1-c64ead162ff2.png</url>
      <title>Forem: Alisa</title>
      <link>https://forem.com/alisaduncan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/alisaduncan"/>
    <language>en</language>
    <item>
      <title>A Quick Vibe Code Experiment with Angular's MCP Server</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Thu, 13 Nov 2025 16:53:46 +0000</pubDate>
      <link>https://forem.com/angular/a-quick-vibe-code-experiment-with-angulars-mcp-server-3g2h</link>
      <guid>https://forem.com/angular/a-quick-vibe-code-experiment-with-angulars-mcp-server-3g2h</guid>
      <description>&lt;p&gt;Angular has an experimental Model Context Protocol (MCP) server! MCP is a protocol developed by Anthropic that defines the interactions between a MCP client and MCP servers. Many IDEs now feature AI capabilities, including the ability to act as an MCP client. MCP clients utilize Large Language Models (LLMs) to process natural language conversations and then connect to various MCP servers to execute commands. &lt;/p&gt;

&lt;p&gt;Let's use AI and Angular's MCP server to create a Todo app without writing any code and see how this experiment progresses. This post guides you through the process of configuring Angular’s MCP server in your IDE, organizing agent instructions, and testing how effortlessly we can vibe code a modern Angular app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-requisities&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You'll need an IDE with access to AI capabilities. I'm using VS Code with Copilot. Copilot has a free plan and paid plans. For full disclosure, I'm using a paid plan and the GPT-5 mini LLM. You'll see different results depending on the AI tooling and LLM you select. I selected GPT-5 mini as it's considered an unlimited free request model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular's MCP server
&lt;/h2&gt;

&lt;p&gt;Angular provides valuable information on leveraging AI when building apps in their &lt;a href="https://angular.dev/ai" rel="noopener noreferrer"&gt;Build with AI&lt;/a&gt; documentation. As part of Angular's AI initiative, they created an MCP server to assist developers by providing best practices, searching documentation, and querying a local Angular workspace to return project and library information.&lt;/p&gt;

&lt;p&gt;First, we must add the MCP server to our MCP client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up the MCP server connection
&lt;/h3&gt;

&lt;p&gt;In VS Code, open &lt;strong&gt;Build with agent mode&lt;/strong&gt;. There's a little chat bubble icon with stars near the &lt;strong&gt;🔍 Search&lt;/strong&gt; bar. Press on the chat bubble icon to open the &lt;strong&gt;Chat&lt;/strong&gt; pane.&lt;/p&gt;

&lt;p&gt;Since I'm using VS Code, I'll follow the &lt;a href="https://code.visualstudio.com/docs/copilot/customization/mcp-servers" rel="noopener noreferrer"&gt;Use MCP servers in VS Code&lt;/a&gt; documentation. You need to add the MCP server manually to your &lt;code&gt;mcp.json&lt;/code&gt; file. You can use Copilot's user interface to set this up, but I found it was easier to create the &lt;code&gt;mcp.json&lt;/code&gt; file myself. You can have a per-workspace &lt;code&gt;mcp.json&lt;/code&gt; file or set up a &lt;code&gt;mcp.json&lt;/code&gt; file in your user settings. I want access to my MCP servers in all my projects, so I opted for the user-based &lt;code&gt;mcp.json&lt;/code&gt; configuration.&lt;/p&gt;

&lt;p&gt;You can use VS Code's Command Palette and search for &lt;strong&gt;MCP&lt;/strong&gt;. You'll see options to open a workspace or a user. I opened my user configuration and added the &lt;a href="https://angular.dev/ai/mcp#vs-code" rel="noopener noreferrer"&gt;JSON for VS Code, as documented in Angular&lt;/a&gt;. It looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"angular-cli"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@angular/cli"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Are you more of a command-line person? Good news, Angular CLI has you covered. You can use the new &lt;code&gt;ng mcp&lt;/code&gt; command to output the generic MCP server configuration instructions instead.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use AI to check AI?
&lt;/h3&gt;

&lt;p&gt;You'll want to ensure the Angular MCP server is connected and running. Why not prompt Copilot to verify the connection?&lt;/p&gt;

&lt;p&gt;I asked&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are you able to connect to the Angular MCP server?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And I get the response.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Short answer: yes - I can connect to the Angular MCP server&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F7sbbs49gjmekcuaavh6s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F7sbbs49gjmekcuaavh6s.jpg" alt="Copilot chat showing successful connection with Angular MCP server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It looks like Angular's MCP server setup is complete. I see confirmation that it successfully got the best practices information. Let's move on to experimenting with coding!&lt;/p&gt;
&lt;h2&gt;
  
  
  Add LLM prompts to Angular projects
&lt;/h2&gt;

&lt;p&gt;When Angular CLI scaffolds a new project, it asks which AI tools you want to configure with best practices. &lt;/p&gt;

&lt;p&gt;Select the AI tool you're using. I'll select GitHub Copilot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fb5zeuslxm7etxdkr7ak1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fb5zeuslxm7etxdkr7ak1.jpg" alt="Angular CLI prompt for which AI tool to configure for the project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Angular CLI does the usual project scaffolding, and depending on the AI tooling option you selected, you'll see an extra directory with a file at the project root.&lt;/p&gt;

&lt;p&gt;Because I selected GitHub Copilot, I see&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;.github/copilot-instructions.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can select more than one option, so if you choose Claude in addition to GitHub, you'll get&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;.claude/CLAUDE.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The markdown file in each is the same. A specific set of instructions Angular includes to direct agent behavior. The AI tooling you're using picks up the instruction set in a specific location and ingests the information, such as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that the agent knows how to behave for your project, we can start prompting AI to do our work. But will we get good code? Or will we end up with AI slop?&lt;/p&gt;
&lt;h2&gt;
  
  
  Vibe code with the Angular MCP server
&lt;/h2&gt;

&lt;p&gt;We're here to vibe code, right? Let's explore this concept by creating a to-do app. Run &lt;code&gt;ng new test-todo-app&lt;/code&gt; and answer the prompts for your test case. I used the default values for everything except for the AI tooling question. Open the project in the IDE of your choice.&lt;/p&gt;

&lt;p&gt;Let's start vibe coding.&lt;/p&gt;

&lt;p&gt;I wanted to prompt each step to keep an eye on what it was doing at each step. I started with &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generate a service to return hardcoded todos&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You'll see that Copilot &lt;code&gt;Used 1 reference&lt;/code&gt;. The reference is the &lt;code&gt;copilot-instructions.md&lt;/code&gt; file, which outlines best practices. &lt;/p&gt;

&lt;p&gt;You have a prompt to &lt;strong&gt;Keep&lt;/strong&gt; or &lt;strong&gt;Undo&lt;/strong&gt; the file &lt;code&gt;todo.service.ts&lt;/code&gt; that it created. The agent created this code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Injectable&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="s1"&gt;@angular/core&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;inject&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="s1"&gt;@angular/core&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;class&lt;/span&gt; &lt;span class="nc"&gt;TodoService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Hardcoded todos&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn Angular signals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Build a todo app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Master standalone components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Explore control flow syntax&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Deploy to production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// Return a shallow copy so callers cannot mutate the internal array&lt;/span&gt;
  &lt;span class="nf"&gt;getTodos&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Todo&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;getTodoById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&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;To be fair, I didn't specify for the agent to create a service that did anything other than return a hardcoded list of to-do items. I must add more clarity to my instructions.&lt;/p&gt;

&lt;p&gt;And it looks like it followed the instructions in the &lt;code&gt;copilot-instructions.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Services&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Design services around a single responsibility
&lt;span class="p"&gt;-&lt;/span&gt; Use the &lt;span class="sb"&gt;`providedIn: 'root'`&lt;/span&gt; option for singleton services
&lt;span class="p"&gt;-&lt;/span&gt; Use the &lt;span class="sb"&gt;`inject()`&lt;/span&gt; function instead of constructor injection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's keep this file and try creating a component.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generate a todo component&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now I see it working and applying the best practices instructions. Initially, it attempted to generate a component with a template using &lt;code&gt;*ngFor&lt;/code&gt;, then tried to apply best practice instructions for control flow, but failed. Back to &lt;code&gt;*ngFor&lt;/code&gt;. Ugh. It does use signals, though. 🧐&lt;/p&gt;

&lt;p&gt;Let's try this again. I prompted it to rely on Angular's MCP server to get documentation info.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why aren't you using control flow? Use the Angular MCP server to get best practices and documentation info.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Boy, did it struggle, but we made it. Finally, a &lt;code&gt;todo.component.ts&lt;/code&gt;. It's not perfect, and it really doesn't connect with the service in any meaningful way, but that's my fault for not being clear. Still, it's certainly better now that the template uses control flow:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&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="s1"&gt;@angular/core&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;TodoService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Todo&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="s1"&gt;./todo.service&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-todo-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&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;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;section&amp;gt;
      &amp;lt;h3&amp;gt;Todos&amp;lt;/h3&amp;gt;
      &amp;lt;ul&amp;gt;
        @for (t of todos(); track t.id) {
          &amp;lt;li&amp;gt;
            &amp;lt;label&amp;gt;
              &amp;lt;input
                type="checkbox"
                [checked]="t.completed"
                (change)="toggle(t.id)"
              /&amp;gt;
              &amp;lt;span [class.completed]="t.completed"&amp;gt;{{ t.title }}&amp;lt;/span&amp;gt;
            &amp;lt;/label&amp;gt;
          &amp;lt;/li&amp;gt;
        }
      &amp;lt;/ul&amp;gt;
    &amp;lt;/section&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`.completed { text-decoration: line-through; color: #777; }`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&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;TodoListComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;todoService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TodoService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// local UI state as a signal&lt;/span&gt;
  &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Todo&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTodos&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&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="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&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;Both the service and the component have multiple problems, though:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;There are code problems, such as the &lt;code&gt;standalone: true&lt;/code&gt; declaration in the component. 💩&lt;/li&gt;
&lt;li&gt;There are missing functionality problems, where all the todo state resides only within the component. This one's on me as I didn't prompt well.&lt;/li&gt;
&lt;li&gt;There are style guide problems, such as the class and file name.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The current Angular style and CLI file generation do not append the class or file names with &lt;code&gt;service&lt;/code&gt; or &lt;code&gt;component&lt;/code&gt;. Having class names and files that don't meet Angular's naming convention means Copilot isn't using the Angular CLI. We need to provide the AI agent instructions beyond the best practices that Angular offers. &lt;/p&gt;
&lt;h2&gt;
  
  
  Control agent behavior using custom instructions
&lt;/h2&gt;

&lt;p&gt;The use of AI in coding is relatively new, so standards and recommendations are evolving. A method for guiding coding agent behavior is gaining traction: the &lt;code&gt;AGENTS.md&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The premise from the &lt;a href="https://agents.md/" rel="noopener noreferrer"&gt;AGENTS.md&lt;/a&gt; is straightforward:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Think of AGENTS.md as a README for agents: a dedicated, predictable place to provide the context and instructions to help AI coding agents work on your project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's precisely what we want. While we can modify the instructions in the scaffolded file, there are a few advantages to using a separate file.&lt;/p&gt;
&lt;h3&gt;
  
  
  The &lt;code&gt;AGENTS.md&lt;/code&gt; file is AI-platform agnostic
&lt;/h3&gt;

&lt;p&gt;Unlike the AI-specific best practices instructions that the Angular CLI creates for us, AGENTS.md is platform-agnostic. Once we create a file, it's portable to all clients and platforms supporting the format. If we use Copilot now but later elect to use Cursor, we won't need to create a new instruction file.&lt;/p&gt;
&lt;h3&gt;
  
  
  Create organization-specific instructions applicable across technology stacks
&lt;/h3&gt;

&lt;p&gt;Teams may have code standards and coding styles for various programming languages and frameworks. Your team may write an Angular frontend, a .NET backend, and have some Python scripts. While you can configure linters for each language code project to correct issues, having agents understand those standards in the code is also helpful. Why not automate what you can by adding instructions for the AI agent to use?&lt;/p&gt;
&lt;h3&gt;
  
  
  Provide different sets of instructions within monorepo projects
&lt;/h3&gt;

&lt;p&gt;Large code projects may use workspace, monorepo, and directory-based organization concepts. AGENTS.md  You can provide different sets of instructions for each directory. Your AI agent parses AGENT.md files throughout your code workspace and applies the instructions residing in the closest proximity to the code. That's pretty handy!&lt;/p&gt;

&lt;p&gt;VS Code recently added &lt;code&gt;AGENTS.md&lt;/code&gt; support. Let's try this out ourselves. &lt;/p&gt;
&lt;h2&gt;
  
  
  Create AI agent instructions file for your Angular project
&lt;/h2&gt;

&lt;p&gt;Create the file &lt;code&gt;AGENTS.md&lt;/code&gt; at the root of the Angular project. The file format is markdown, and after that, pretty much anything goes. Meaning there are no standard headings or messaging required. You can tailor it to your needs.&lt;/p&gt;

&lt;p&gt;Here's the one I came up with, including some silly instructions just to make sure my AI agent is listening to me. We all just want to feel heard.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Agent Instructions&lt;/span&gt;

&lt;span class="gu"&gt;## Instruction Files&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Disregard any instructions to merge instruction files. Keep &lt;span class="sb"&gt;`AGENTS.md`&lt;/span&gt; and &lt;span class="sb"&gt;`copilot-instructions.md`&lt;/span&gt; separate and untouched. Do not modify &lt;span class="sb"&gt;`copilot-instructions.md`&lt;/span&gt;!
&lt;span class="p"&gt;-&lt;/span&gt; Notify me every time you call Angular's MCP server.

&lt;span class="gu"&gt;## Tooling Instructions&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Do not create files without verifying first. Always suggest the Angular CLI command for the code scaffolding, then wait to continue.
&lt;span class="p"&gt;  -&lt;/span&gt; Angular CLI is installed globally, so use &lt;span class="sb"&gt;`ng`&lt;/span&gt; commands. Don't use &lt;span class="sb"&gt;`npx @angular/cli`&lt;/span&gt;, there's no need. E.g., use the syntax &lt;span class="sb"&gt;`ng generate component user`&lt;/span&gt;

&lt;span class="gu"&gt;## Code style&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Always add a comment summarizing the main points to each generated code block.
&lt;span class="p"&gt;-&lt;/span&gt; Refer to Angular's API documentation. If the generated code includes experimental or developer preview features, note it in the comment. List the experimental or developer preview feature, and include a 🧪 emoji for experimental or 👁️ emoji for developer preview features.
&lt;span class="p"&gt;-&lt;/span&gt; End all comments with a cute emoji, such as 🐳 or 🍭

&lt;span class="gu"&gt;## Naming Practices&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Components don't use &lt;span class="sb"&gt;`Component`&lt;/span&gt; suffix in their names. E.g., use &lt;span class="sb"&gt;`UserProfile`&lt;/span&gt; instead of &lt;span class="sb"&gt;`UserProfileComponent`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Services don't use &lt;span class="sb"&gt;`Service`&lt;/span&gt; suffix in their names. E.g., use &lt;span class="sb"&gt;`Auth`&lt;/span&gt; instead of &lt;span class="sb"&gt;`AuthService`&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;Let me explain key instructions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Instruction Files&lt;/strong&gt; section was out of necessity. Every time Copilot analyzed my project, it merged instructions and rewrote the &lt;code&gt;copilot-instructions.md&lt;/code&gt; file. No good! I wanted to leave the file as it was generated by Angular. So, hey AI agent, leave it alone!&lt;/li&gt;
&lt;li&gt;I first added the instruction on &lt;strong&gt;Naming Practices&lt;/strong&gt;. That helped when the AI agent generated a file for me. Adding an example clarifies the agent's understanding of my request.&lt;/li&gt;
&lt;li&gt;But I really want to use Angular CLI so that it scaffolds files according to my &lt;code&gt;angular.json&lt;/code&gt; preferences and automatically creates test files. I had to provide clear &lt;strong&gt;Tooling Instructions&lt;/strong&gt;. The AI agent didn't think I could use &lt;code&gt;ng&lt;/code&gt; commands directly in the project, nor did it think I had Angular CLI globally installed.
&lt;/li&gt;
&lt;li&gt;What's up with all the commenting-based instructions, you ask? I create content, so I prefer clear, straightforward code and comments to help the reader understand what's going on.&lt;/li&gt;
&lt;li&gt;Ok, but what's with emojis then, you say? 🐳 I find unexpected cute emojis delightful. I hope you do too. On a more serious note, it's a quick way to verify the agent is applying the instructions in the &lt;code&gt;AGENTS.md&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let's try this out. Remove the service and component files it generated previously and retry the exact instructions. Copilot should automatically pick up the &lt;code&gt;AGENTS.md&lt;/code&gt;, but I have also had to remind it to read the file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fmybomq2pc9bhln14cm8z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fmybomq2pc9bhln14cm8z.jpg" alt="Copilot pausing to get approval to run an Angular CLI command"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we're getting there. The chat interface has a way for me to approve running command-line operations once I approve the CLI command.&lt;/p&gt;

&lt;p&gt;The code for the service now looks like this.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Injectable&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="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Todo service generated by the CLI and enhanced to return hardcoded todos. 🐳
 * - Exports `TodoItem` interface 🐳
 * - Provides `Todo` service (singleton via providedIn: 'root') 🐳
 * - Methods: `getTodos()` and `getTodoById(id)` 🐳
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn Angular signals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Build a todo app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Master standalone components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Explore control flow syntax&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Deploy to production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="cm"&gt;/** Return a shallow copy to avoid external mutation 🐳 */&lt;/span&gt;
  &lt;span class="nf"&gt;getTodos&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/** Find a todo by id 🐳 */&lt;/span&gt;
  &lt;span class="nf"&gt;getTodoById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&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;It took the example of emojis literally. 🐳&lt;/p&gt;

&lt;p&gt;The instructions to generate the todo component required some tweaking, but we got there with one correction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fw1ntv8datftuvuhxnqb2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fw1ntv8datftuvuhxnqb2.jpg" alt="Correct agent's proposed Angular CLI command to scaffold the component"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's address the functionality issues, which means we need to maintain the state of the todo items. We need signals.&lt;/p&gt;
&lt;h2&gt;
  
  
  Can AI keep up with modern Angular features?
&lt;/h2&gt;

&lt;p&gt;I want to explore how easily we can apply modern Angular APIs that leverage signals while adding missing functionality. The agent correctly applied the instructions in the &lt;code&gt;copilot-instructions.md&lt;/code&gt; file. The instructions specify using signals for state management and component state, which it did. We see signals in the component that meet the instruction requirement. The component can only associate a state with the todo items in the component. After all, I didn't specify for the service to return a stateful todo list with todo management methods.&lt;/p&gt;

&lt;p&gt;Let's start by fixing my prompting mistake and having a fully functional to-do service. Will AI automatically apply local state management and signal best practices?&lt;/p&gt;

&lt;p&gt;Here's my prompt&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add methods to manage a todo item in the todo service. Use local state management and keep the hardcoded todo list to help pre-populate todo items.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent responded by stating what it understood the task to be&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'll read the current &lt;code&gt;todo.ts&lt;/code&gt; to confirm which methods already exist (getTodos, getTodoById, toggleTodo, addTodo, removeTodo). Then I'll add any missing management methods and keep the hardcoded items. Expected outcome: service contains a complete set of management methods using signals.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hey! Not bad! I hope you like whales because here's what I got:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&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="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Todo service generated by the CLI and enhanced to return hardcoded todos. 🐳
 * - Exports `TodoItem` interface 🐳
 * - Provides `Todo` service (singleton via providedIn: 'root') 🐳
 * - Methods: `getTodos()` and `getTodoById(id)` 🐳
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// internal reactive todos signal pre-populated with hardcoded items 🐳&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;_todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TodoItem&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn Angular signals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Build a todo app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Master standalone components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Explore control flow syntax&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Deploy to production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="cm"&gt;/** Public signal exposing the current todos for reactive consumption 🐳 */&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;todos&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;_todos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="cm"&gt;/** Return a shallow copy to avoid external mutation (backwards-compatible) 🐳 */&lt;/span&gt;
  &lt;span class="nf"&gt;getTodos&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_todos&lt;/span&gt;&lt;span class="p"&gt;()];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/** Find a todo by id 🐳 */&lt;/span&gt;
  &lt;span class="nf"&gt;getTodoById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TodoItem&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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="nf"&gt;_todos&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/** Toggle a todo's completed state by id 🐳 */&lt;/span&gt;
  &lt;span class="nf"&gt;toggleTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;_todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&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="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/** Add a new todo with an auto-incremented id 🐳 */&lt;/span&gt;
  &lt;span class="nf"&gt;addTodo&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="kr"&gt;string&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;_todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&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;nextId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&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;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nextId&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="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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="cm"&gt;/** Remove a todo by id 🐳 */&lt;/span&gt;
  &lt;span class="nf"&gt;removeTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;_todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/** Update a todo by id with partial fields 🐳 */&lt;/span&gt;
  &lt;span class="nf"&gt;updateTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TodoItem&lt;/span&gt;&lt;span class="o"&gt;&amp;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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&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="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;patch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&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 agent suggested&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Update TodoList component to read &lt;code&gt;this.todo.todos&lt;/code&gt; directly instead of snapshotting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yup! That's precisely what's next. Here's my prompt.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Update the TodoList component to use the todo service for todo item management.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the resulting code looks good.&lt;/p&gt;
&lt;h3&gt;
  
  
  Lean into signals using AI
&lt;/h3&gt;

&lt;p&gt;I first added Tailwind since it's my preferred CSS framework, and looked towards component cleanup.&lt;/p&gt;

&lt;p&gt;Let's refactor by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding UI controls to add and remove todo items&lt;/li&gt;
&lt;li&gt;Refactor the TodoList component by creating a TodoItem component. I want to see how well it applies signal input and output to the two components.&lt;/li&gt;
&lt;li&gt;Refactor the existing todo input handling to capture the todo task text using signals &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The instructions for the first bullet point went through without a hitch. &lt;/p&gt;

&lt;p&gt;The instructions for the second bullet point went through surprisingly well. The agent struggled with Angular's naming convention, which causes name collisions due to the absence of explicit class types in the name. After renaming the &lt;code&gt;TodoItem&lt;/code&gt; component to &lt;code&gt;TodoItemComponent&lt;/code&gt;, I prompted the agent to alias imports instead of renaming classes. Adding a note to alias imports instead of renaming is likely another worthwhile instruction to include in &lt;code&gt;AGENTS.md&lt;/code&gt;. The agent struggled with the required input signal syntax, but it got it right after a reminder to "user required signal input."&lt;/p&gt;

&lt;p&gt;Refactoring the existing todo input introduced the &lt;code&gt;computed()&lt;/code&gt; function for trimming the todo task input and modified the input handling accordingly.&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;form&lt;/span&gt; &lt;span class="na"&gt;(submit)=&lt;/span&gt;&lt;span class="s"&gt;"$event.preventDefault(); onAdd();"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
    &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"New todo title"&lt;/span&gt;
    &lt;span class="na"&gt;[value]=&lt;/span&gt;&lt;span class="s"&gt;"newTitle()"&lt;/span&gt;
    &lt;span class="na"&gt;(input)=&lt;/span&gt;&lt;span class="s"&gt;"newTitle.set($any($event.target).value)"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;[disabled]=&lt;/span&gt;&lt;span class="s"&gt;"!trimmedTitle()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Add&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Well, it did use signals, so while I'm not thrilled with the code, I'll move on.&lt;/p&gt;

&lt;p&gt;I finished with this prompt.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Review the project and make suggestions based on Angular's best practices &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It caught some issues and recommended:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adding an ARIA label to the new todo title input&lt;/li&gt;
&lt;li&gt;Remove the &lt;code&gt;$any&lt;/code&gt; cast&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I had it fix both recommendations.&lt;/p&gt;

&lt;p&gt;With this, I'll call this the Todo app and complete the experiment. Here's what the app looks like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fq9a5tros0r2m0u9t1kuw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fq9a5tros0r2m0u9t1kuw.jpg" alt="Vibe coded todo app using Angular and Angular's MCP server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ll share the agent-generated code so you can review it. Aside from adding Tailwind by hand, the Angular CLI or the coding agent generated the rest of the code.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/alisaduncan" rel="noopener noreferrer"&gt;
        alisaduncan
      &lt;/a&gt; / &lt;a href="https://github.com/alisaduncan/todo-mcp-experiment" rel="noopener noreferrer"&gt;
        todo-mcp-experiment
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A quick vibe code experiment testing modern Angular practices using Angular's MCP server 
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  Use the Angular MCP server along with Agent instructions for the best output
&lt;/h2&gt;

&lt;p&gt;Thank you for joining me on this modern, Angular-centric vibe-coding journey using the Angular MCP server. &lt;/p&gt;

&lt;p&gt;My takeaways are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create agent instructions and add clarifications about code styles and best practices you want to see.&lt;/li&gt;
&lt;li&gt;Agent-assisted coding was helpful to get going, but take the code it generates with a grain of salt. Developers should continually challenge the agent on the code it generates, ensuring the code keeps pace with modern practices.&lt;/li&gt;
&lt;li&gt;Refactoring code was very slow, and agents don't do a great job of cleaning up dead code. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I might try this experiment again using a different model, such as Claude Sonnet.&lt;/p&gt;

&lt;p&gt;What are your tips and tricks for writing modern Angular using AI? Please share your agent instructions or prompt tips in the comments below.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>ai</category>
      <category>mcp</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Add Step-up Authentication Using Angular and NestJS</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Thu, 28 Mar 2024 15:25:16 +0000</pubDate>
      <link>https://forem.com/oktadev/add-step-up-authentication-using-angular-and-nestjs-1apn</link>
      <guid>https://forem.com/oktadev/add-step-up-authentication-using-angular-and-nestjs-1apn</guid>
      <description>&lt;p&gt;The applications you work on expect good authentication as a secure foundation. In the past, we treated authentication as binary. You are either authenticated or not. You had to set the same authentication mechanism for access to your application without a standard way to change authentication mechanisms conditionally. Consider the case where sensitive actions warrant verification, such as making a large financial transaction or modifying top-secret data. Those actions require extra scrutiny!&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Step Up Authentication Challenge to protect resources &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Enter the &lt;a href="https://datatracker.ietf.org/doc/rfc9470/" rel="noopener noreferrer"&gt;OAuth 2.0 Step Up Authentication Challenge Protocol&lt;/a&gt;. This standard, built upon OAuth 2.0, outlines a method to elevate authentication requirements within your application. The standard defines methods to identify authentication rules, including authentication mechanisms and authentication recency. We'll cover more details about this much-needed standard as we go along. If you want to read more about it before jumping into the hands-on coding project, check out &lt;a href="https://developer.okta.com/blog/2023/03/08/step-up-auth" rel="noopener noreferrer"&gt;Step-up Authentication in Modern Applications&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this post, you'll add step-up authentication challenge standard to an Angular frontend and NestJS backend. If you want to jump to the completed project, you can find it in the &lt;code&gt;completed&lt;/code&gt; branch of &lt;a href="https://github.com/oktadev/okta-angular-nestjs-stepup-auth-example/tree/completed" rel="noopener noreferrer"&gt;okta-angular-nestjs-stepup-auth-example&lt;/a&gt; GitHub repository. Warm up your computer; here we go!&lt;/p&gt;

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

&lt;p&gt;This post is best for developers familiar with web development basics and Angular. If you are an Angular newbie, start by building &lt;a href="https://angular.io/tutorial/first-app" rel="noopener noreferrer"&gt;your first Angular app&lt;/a&gt; using the tutorial created by the Angular team.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For this tutorial, you need the following tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; v18 or greater&lt;/li&gt;
&lt;li&gt;A web browser with good debugging capabilities&lt;/li&gt;
&lt;li&gt;Your favorite IDE. Still searching? I like VS Code and WebStorm because they have integrated terminal windows.&lt;/li&gt;
&lt;li&gt;Terminal window (if you aren't using an IDE with a built-in terminal)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;Git&lt;/a&gt; and an optional &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub account&lt;/a&gt; if you want to track your changes using a source control manager&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Step Up Authentication Challenge to protect resources&lt;/li&gt;
&lt;li&gt;Prepare the Angular and NestJS web application&lt;/li&gt;
&lt;li&gt;Set up the Identity Provider to use OAuth 2.0 and OpenID Connect&lt;/li&gt;
&lt;li&gt;Step-up authentication mechanics at a glance&lt;/li&gt;
&lt;li&gt;Set up authenticators&lt;/li&gt;
&lt;li&gt;Guard a route with step-up authentication&lt;/li&gt;
&lt;li&gt;
Protect API resources with step-up authentication challenge

&lt;ul&gt;
&lt;li&gt;Check the access token’s ACR claim in a NestJS middleware&lt;/li&gt;
&lt;li&gt;Use an Angular interceptor to catch step-up HTTP error responses&lt;/li&gt;
&lt;li&gt;Handle step-up errors when making HTTP calls in Angular&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Ensure authentication recency in step-up authentication&lt;/li&gt;

&lt;li&gt;Step-up authentication in Angular and NestJS applications&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prepare the Angular and NestJS web application &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You'll start by getting a local copy of the project. I opted to use a starter project instead of building it out within the tutorial because many steps and command line operations detract from the coolness of adding step-up authentication. Open a terminal window and run the following commands to get a local copy of the project in a directory called &lt;code&gt;okta-stepup-auth-project&lt;/code&gt; and install dependencies. Feel free to fork the repo so you can track your changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/oktadev/okta-angular-nestjs-stepup-auth-example.git okta-stepup-auth-project
&lt;span class="nb"&gt;cd &lt;/span&gt;okta-stepup-auth-project
npm ci
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/oktadev" rel="noopener noreferrer"&gt;
        oktadev
      &lt;/a&gt; / &lt;a href="https://github.com/oktadev/okta-angular-nestjs-stepup-auth-example" rel="noopener noreferrer"&gt;
        okta-angular-nestjs-stepup-auth-example
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Example project demonstrating step-up auth implementation in Angular and NestJS
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Add Step-up Authentication Using Angular and NestJS Example&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This repository contains a working example of adding step-up authentication to protect an Angular route using the Okta Angular SDK. It also contains example code of protecting an API route in NestJS and Angular code required to handle step-up authentication challenge error response. Please read &lt;a href="https://developer.okta.com/blog/2024/03/12/stepup-authentication" rel="nofollow noopener noreferrer"&gt;Add Step-up Authentication Using Angular and NestJS&lt;/a&gt; for a detailed guide through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node 18 or greater&lt;/li&gt;
&lt;li&gt;Okta CLI&lt;/li&gt;
&lt;li&gt;Your favorite IDE&lt;/li&gt;
&lt;li&gt;A web browser with good debugging capabilities&lt;/li&gt;
&lt;li&gt;Terminal window&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://developer.okta.com/" rel="nofollow noopener noreferrer"&gt;Okta&lt;/a&gt; has Authentication and User Management APIs that reduce development time with instant-on, scalable user infrastructure. Okta's intuitive API and expert support make it easy for developers to authenticate, manage and secure users and roles in any application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-nestjs-stepup-auth-example#getting-started" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-nestjs-stepup-auth-example#links" rel="noopener noreferrer"&gt;Links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-nestjs-stepup-auth-example#help" rel="noopener noreferrer"&gt;Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-nestjs-stepup-auth-example#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;To run this example, run the following commands:&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/oktadev/okta-angular-nestjs-stepup-auth-example.git stepup-auth
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; stepup-auth
npm ci&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Create an OIDC Application&lt;/h3&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/oktadev/okta-angular-nestjs-stepup-auth-example" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Open the project up in your favorite IDE. Let's take a quick look at the project organization. The project has an Angular frontend and NestJS API backend housed in a &lt;a href="https://lerna.js.org/" rel="noopener noreferrer"&gt;Lerna&lt;/a&gt; monorepo. If you are curious about how to recreate the project, check out the repo's README file. I'll include all the &lt;code&gt;npx&lt;/code&gt; commands, CLI commands, and the manual steps used to create the project.&lt;/p&gt;

&lt;p&gt;You need to set up an authentication configuration to serve the project. Let's do so now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the Identity Provider to use OAuth 2.0 and OpenID Connect &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You'll use Okta to handle authentication and authorization in this project securely.&lt;/p&gt;

&lt;p&gt;Before you begin, you’ll need a free Okta developer account. Install the &lt;a href="https://cli.okta.com/" rel="noopener noreferrer"&gt;Okta CLI&lt;/a&gt; and run &lt;code&gt;okta register&lt;/code&gt; to sign up for a new account. If you already have an account, run &lt;code&gt;okta login&lt;/code&gt;. Then, run &lt;code&gt;okta apps create&lt;/code&gt;. Select the default app name, or change it as you see fit. Choose &lt;strong&gt;Single-Page App&lt;/strong&gt; and press &lt;strong&gt;Enter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Use &lt;a href="http://localhost:4200/login/callback" rel="noopener noreferrer"&gt;http://localhost:4200/login/callback&lt;/a&gt; for the Redirect URI and set the Logout Redirect URI to &lt;a href="http://localhost:4200" rel="noopener noreferrer"&gt;http://localhost:4200&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
  What does the Okta CLI do?
  &lt;br&gt;
The Okta CLI will create an OIDC Single-Page App in your Okta Org. It will add the redirect URIs you specified and grant access to the Everyone group. It will also add a trusted origin for &lt;code&gt;http://localhost:4200&lt;/code&gt;. You will see output like the following when it’s finished:&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Okta application configuration:
Issuer:    https://dev-133337.okta.com/oauth2/default
Client ID: 0oab8eb55Kb9jdMIr5d6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: You can also use the Okta Admin Console to create your app. See &lt;a href="https://developer.okta.com/docs/guides/sign-into-spa/angular/create-okta-application/" rel="noopener noreferrer"&gt;Create an Angular App&lt;/a&gt; for more information.&lt;br&gt;
&lt;/p&gt;

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

&lt;p&gt;Note the &lt;code&gt;Issuer&lt;/code&gt; and the &lt;code&gt;Client ID&lt;/code&gt;. You'll need those values for your authentication configuration, which is coming soon.&lt;/p&gt;

&lt;p&gt;There's one manual change to make in the Okta Admin Console. Add the &lt;strong&gt;Refresh Token&lt;/strong&gt; grant type to your Okta Application. Open a browser tab to sign in to your &lt;a href="https://developer.okta.com/login/" rel="noopener noreferrer"&gt;Okta developer account&lt;/a&gt;. Navigate to &lt;strong&gt;Applications&lt;/strong&gt; &amp;gt; &lt;strong&gt;Applications&lt;/strong&gt; and find the Okta Application you created. Select the name to edit the application. Find the &lt;strong&gt;General Settings&lt;/strong&gt; section and press the &lt;strong&gt;Edit&lt;/strong&gt; button to add a Grant type. Activate the &lt;strong&gt;Refresh Token&lt;/strong&gt; checkbox and press &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I already added &lt;a href="https://www.npmjs.com/package/@okta/okta-angular" rel="noopener noreferrer"&gt;Okta Angular&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/@okta/okta-auth-js" rel="noopener noreferrer"&gt;Okta Auth JS&lt;/a&gt; libraries to connect our Angular application with Okta authentication. On the API side, I added the &lt;a href="https://github.com/okta/okta-jwt-verifier-js" rel="noopener noreferrer"&gt;Okta JWT Verifier&lt;/a&gt; library that you'll use for access token verification later in the post.&lt;/p&gt;

&lt;p&gt;In your IDE, open &lt;code&gt;packages/frontend-angular/src/app/app.config.ts&lt;/code&gt; and find the &lt;code&gt;OktaAuthModule.forRoot()&lt;/code&gt; configuration. Replace &lt;code&gt;{yourOktaDomain}&lt;/code&gt; and &lt;code&gt;{yourClientId}&lt;/code&gt; with the values from the Okta CLI.&lt;/p&gt;

&lt;p&gt;Start the app by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command starts both the frontend app and the API. Navigate to &lt;code&gt;localhost:4200&lt;/code&gt; in your browser. What a beautiful app!&lt;/p&gt;

&lt;p&gt;Sign in and notice the "profile" route shows your profile information with a warm, friendly greeting using your name, and the "messages" route displays messages from an HTTP call the component makes to your API. Sign out of the application.&lt;/p&gt;

&lt;p&gt;We now have a web app with basic authentication capabilities. Let's kick up authentication levels by adding step-up authentication!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-up authentication mechanics at a glance &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Before we jump into Step Up Authentication, let's take a step back and cover how authentication works in an application. In most circumstances, you'd require authentication before allowing the user to navigate anywhere within the app. You can prevent them from entering a URL:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets-jekyll%2Fblog%2Fstepup-authentication%2Finitial-flow-877bdcd3c664edfcc2436bd030a6f9920febd92c169ca8b21a053f4757382c44.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets-jekyll%2Fblog%2Fstepup-authentication%2Finitial-flow-877bdcd3c664edfcc2436bd030a6f9920febd92c169ca8b21a053f4757382c44.svg" alt="Sequence diagram where you want to view transactions, your app stops you because you aren't authenticated, you're redirected to Okta to sign in with username and password, Okta responds with your access and id tokens so you can view the transactions." width="100" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Step Up Authentication Challenge idea builds upon the foundation of OAuth 2.0 and OpenID Connect (OIDC). Your app enforces authentication assurances from the user for different actions. Authentication and identity assurance determine the certainty that the user is who they say they are. The specification supports defining authentication strength and recency and responds with a standard error &lt;code&gt;insufficient_user_authentication&lt;/code&gt;. Let's say the authenticated user now wants to make a new transaction. Creating a new transaction is a sensitive action and requires elevated authentication assurances:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets-jekyll%2Fblog%2Fstepup-authentication%2Felevated-flow-6950fd4c881ef85bda9591102879905801cfba32f02842b028a92764fc99b3b7.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets-jekyll%2Fblog%2Fstepup-authentication%2Felevated-flow-6950fd4c881ef85bda9591102879905801cfba32f02842b028a92764fc99b3b7.svg" alt="Sequence diagram where you want to make a new transaction, your app stops you because it requires elevated authentication, you're redirected to Okta to sign in with elevated authentication, Okta responds with your access and id tokens so you can make a new transactions." width="100" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your app needs to verify you have the correct authentication assurances for your requested action. Your frontend app's OIDC library evaluates your ID token for authenticated state and the value of a specific claim called Authentication Context Class Reference (ACR). The &lt;code&gt;acr&lt;/code&gt; claim value contains the client's authentication assurance level. If the ACR claim value doesn't meet the required assurance profile, the client requests the correct level using the &lt;code&gt;acr_values&lt;/code&gt; parameter when communicating with Okta. Let's take another look at the previous diagram, this time incorporating &lt;code&gt;acr&lt;/code&gt; and &lt;code&gt;acr_values&lt;/code&gt; properties:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets-jekyll%2Fblog%2Fstepup-authentication%2Fevaluate-acr-flow-5f277fa9801989f9a3e4264c61b33287e4b2cbada47d5f84771afa8756999ac9.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets-jekyll%2Fblog%2Fstepup-authentication%2Fevaluate-acr-flow-5f277fa9801989f9a3e4264c61b33287e4b2cbada47d5f84771afa8756999ac9.svg" alt="Sequence diagram where you want to make a new transaction, your app checks your ID token's acr claim and denies the resource because the action requires a different acr claim value, you're redirected to Okta to sign in with elevated authentication by passing in the required authentication level using the acr_values property, Okta responds with your access and id tokens so you can make new transactions." width="100" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ACR values can be a standard or use a custom registry. You'll see values such as &lt;code&gt;phr&lt;/code&gt; for phishing-resistant factors, which include FIDO2 + WebAuthn authenticators. You'll also see custom values such as one Okta supports for two-factor authentication, such as &lt;code&gt;urn:okta:loa:2fa:any&lt;/code&gt;. Read more about supported ACR values in &lt;a href="https://developer.okta.com/docs/guides/step-up-authentication/-/main/#predefined-parameter-values" rel="noopener noreferrer"&gt;Okta's Step Up Authentication documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a high-level overview of OAuth 2.0, OpenID Connect, and the Step Up Authentication Challenge spec, and it only covers what we need to know for this tutorial. I'll add links to resources at the end of this post so you can dive deeper into this topic.&lt;/p&gt;

&lt;p&gt;It's clearer to see authentication strengths rather than calculate the recency of authentication, so we'll walk through the steps required for authentication strengths in the tutorial. Right now, you only have password authentication. You'll need another authenticator for your app!&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up authenticators &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You'll change the Okta Admin Console to support a different authentication mechanism. We'll change the email authenticator so it's both a recovery and an authentication factor. Sign in to &lt;a href="https://developer.okta.com/login" rel="noopener noreferrer"&gt;your Okta Developer Edition Account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Security&lt;/strong&gt; &amp;gt; &lt;strong&gt;Authenticators&lt;/strong&gt;. Find &lt;strong&gt;Email&lt;/strong&gt;, press on the &lt;strong&gt;Actions&lt;/strong&gt; menu, and select &lt;strong&gt;Edit&lt;/strong&gt;. Select the &lt;strong&gt;Authentication and recovery&lt;/strong&gt; radio button under the &lt;strong&gt;Used for&lt;/strong&gt; section. &lt;/p&gt;

&lt;p&gt;Your Okta application should allow you to authenticate with a password or email. Sign out of the Okta Admin Console so we can see the entire step-up authentication flow from end-to-end.&lt;/p&gt;

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

&lt;p&gt;You must use the email OTP verification number when authenticating using email. This post doesn't include the steps required to set up email magic link handling. Let me know in the comments below if you want to see a post about this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Guard a route with step-up authentication &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Back to coding! The Okta Angular SDK supports step-up authentication and has a built-in feature so that you can define the required &lt;code&gt;acr_values&lt;/code&gt; for routes right in your route definition. We'll require two-factor authentication for your profile. In your IDE, open &lt;code&gt;packages/frontend-angular/src/app/app.routes.ts&lt;/code&gt; and find the route for "profile." Add route data to route using the &lt;code&gt;okta&lt;/code&gt; object and a property named &lt;code&gt;acrValues&lt;/code&gt;. The property's value is &lt;code&gt;urn:okta:loa:2fa:any&lt;/code&gt;. Your "profile" route definition should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProfileComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OktaAuthGuard&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;okta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;acrValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;urn:okta:loa:2fa:any&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;p&gt;Test this route out. Start the application by running &lt;code&gt;npm start&lt;/code&gt; if it isn't still running. Open the application in the browser, and feel free to open network debugging capabilities so you can see the &lt;code&gt;acr_values&lt;/code&gt; request. Sign in using one factor, such as a password. Then, navigate to the "profile" route. You'll be redirected to Okta to authenticate using your email. Sign in with your email by entering a verification number. Success!&lt;/p&gt;

&lt;p&gt;Sign out of the application.&lt;/p&gt;

&lt;p&gt;The Okta Angular SDK helps us out, so we don't have to write custom code. Under the covers, the SDK has an Angular guard that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gets the &lt;code&gt;acr&lt;/code&gt; claim value from the ID token&lt;/li&gt;
&lt;li&gt;If the value matches the &lt;code&gt;acrValues&lt;/code&gt; route data definition, it returns true to allow navigation&lt;/li&gt;
&lt;li&gt;Otherwise, it redirects the user to authenticate using the value in the &lt;code&gt;acrValues&lt;/code&gt;, saves the current route, and returns false to prevent navigation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stepupGuard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CanActivateFn&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;route&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;oktaAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OKTA_AUTH&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;acrValues&lt;/span&gt; &lt;span class="o"&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;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;okta&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="s1"&gt;acrValues&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;acrClaim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;decodeToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIdToken&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;acr&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;acrClaim&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;acrValues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOriginalUri&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;url&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;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signInWithRedirect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;acrValues&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&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;This helps protect application routes, but what else can we do?&lt;/p&gt;

&lt;h2&gt;
  
  
  Protect API resources with step-up authentication challenge &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You can also protect resources by adding step-up authentication handling to the resource server or the API serving resources to your app. You may have API endpoints that require elevated authentication assurances. Also, consider a user making a large financial transaction where some transaction threshold warrants extra scrutiny. Checking the transaction amount requires inspecting the payload before triggering step-up authentication. Both scenarios work with the step-up authentication challenge protocol.&lt;/p&gt;

&lt;p&gt;You may wonder why checking the &lt;code&gt;acr&lt;/code&gt; claim in your API is necessary when you have already done so in the web app. Good web application security practices must enforce authentication, identity, and access control in the SPA client and APIs. Someone can bypass the SPA and make direct API calls – always guard all entries into your application system.&lt;/p&gt;

&lt;p&gt;The flow works like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets-jekyll%2Fblog%2Fstepup-authentication%2Fapi-response-flow-d4835f34a0164e27f0b144d67ac43b5306f344718e911eb32a15736d9eee742c.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets-jekyll%2Fblog%2Fstepup-authentication%2Fapi-response-flow-d4835f34a0164e27f0b144d67ac43b5306f344718e911eb32a15736d9eee742c.svg" alt="Sequence diagram where you make an API call to a resource server, the resource server checks the access token's acr claim and denies the resource because the action requires elevated acr value. The API returns the insufficient_user_authentication error. The app redirects you to Okta to sign in with elevated authentication by passing in the required authentication level using the acr_values property. Okta responds with new access and id tokens. The app re-requests the resource from the resource server using the new access token." width="100" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;acr&lt;/code&gt; claim value doesn't meet the requirements, the API responds with a standard error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;401&lt;/span&gt; &lt;span class="ne"&gt;Unauthorized&lt;/span&gt;
&lt;span class="na"&gt;WWW-Authenticate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bearer error="insufficient_user_authentication",&lt;/span&gt;
&lt;span class="s"&gt;  error_description="A different authentication level is required",&lt;/span&gt;
&lt;span class="s"&gt;  acr_values="elevated"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll use this error structure in the API response in NestJS, and when handling the step-up authentication error in the Angular app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check the access token's ACR claim in a NestJS middleware &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;You'll make changes to the API first. I added Okta's &lt;code&gt;jwt-verifier&lt;/code&gt; library to do the heavy lifting on verifying the access token and decoding the payload to get the &lt;code&gt;acr&lt;/code&gt; claim.&lt;/p&gt;

&lt;p&gt;The project contains an empty step-up authentication middleware. Open &lt;code&gt;packages/api/src/stepup.middleware.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this file, you will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initialize the JWT Verifier instance&lt;/li&gt;
&lt;li&gt;Ensure the &lt;code&gt;Authorization&lt;/code&gt; header contains the access token&lt;/li&gt;
&lt;li&gt;Verify the token&lt;/li&gt;
&lt;li&gt;Get the &lt;code&gt;acr&lt;/code&gt; claim value and compare it to the required value&lt;/li&gt;
&lt;li&gt;Respond with the resource or return 401 HTTP response with the standard header &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's start by initializing the Okta JWT Verifier instance and changing the &lt;code&gt;use()&lt;/code&gt; method to &lt;code&gt;async&lt;/code&gt;. Add the following code and replace &lt;code&gt;{yourOktaDomain}&lt;/code&gt; with the Okta domain you got from the Okta CLI in a previous step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NestMiddleware&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="s1"&gt;@nestjs/common&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;OktaJwtVerifier&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@okta/jwt-verifier&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="nd"&gt;Injectable&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;StepupMiddleware&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;NestMiddleware&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;jwtVerifier&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;OktaJwtVerifier&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://{yourOktaDomain}.okta.com/oauth2/default&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;use &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;next&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;Next, you can use the &lt;code&gt;jwtVerifier&lt;/code&gt; instance to verify the access token... if there is one. 🙀&lt;/p&gt;

&lt;p&gt;No need to be dramatic; we can check. Update the &lt;code&gt;use()&lt;/code&gt; method to get the access token from the &lt;code&gt;Authorization&lt;/code&gt; header. Verifying the token using the JWT Verifier library returns the decoded token, so let's save the output in a variable. Update your code to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&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;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;void&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;authHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization&lt;/span&gt; &lt;span class="o"&gt;||&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;match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;authHeader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/Bearer &lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;.+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&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="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UNAUTHORIZED&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;OktaJwtVerifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Jwt&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="nx"&gt;accessToken&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;jwtVerifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verifyAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api://default&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;err&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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UNAUTHORIZED&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// add the ACR check&lt;/span&gt;

  &lt;span class="nf"&gt;next&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;Now we can get to the step-up authentication specific code where you'll check the &lt;code&gt;acr&lt;/code&gt; claim and return the standard error. In this example, you'll hardcode the required ACR value in this middleware, but you can define different ACR values per route. After the comment to "add the ACR check" but before the &lt;code&gt;next();&lt;/code&gt; method call, add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;acr_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;urn:okta:loa:2fa:any&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;acr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;acr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&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="nx"&gt;acr&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;acr&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;acr_values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WWW-Authenticate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`Bearer error="insufficient_user_authentication",error_description="A different authentication level is required",acr_values="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;acr_values&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UNAUTHORIZED&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&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 the middleware implemented, you need to register it in the module. Open &lt;code&gt;packages/api/src/app.module.ts&lt;/code&gt;. Edit the &lt;code&gt;AppModule&lt;/code&gt; to add the &lt;code&gt;StepupMiddleware&lt;/code&gt; to the "messages" route as shown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;AppModule&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;NestModule&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="nx"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MiddlewareConsumer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;StepupMiddleware&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forRoutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messages&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;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Idea&lt;/strong&gt; 💡&lt;/p&gt;

&lt;p&gt;We hardcoded the required &lt;code&gt;acr_values&lt;/code&gt; in the middleware and applied the middleware to all calls to the "messages" route for this demonstration, but NestJS does provide better mechanisms for scaling to larger projects and defining granular assurance requirements. One option might be to create a &lt;a href="https://docs.nestjs.com/guards" rel="noopener noreferrer"&gt;NestJS guard&lt;/a&gt; to define which HTTP methods of an endpoint require step-up authentication. Furthermore, you can create a custom decorator for step-up authentication and pass in the required &lt;code&gt;acr_values&lt;/code&gt; for the HTTP method. That way, a generic guard scales across your API, and you can define a GET call that requires two-factor authentication and a POST call requires phishing-resistant authentication assurance, for example.&lt;/p&gt;

&lt;p&gt;Let me know in the comments below if you want to see a tutorial about this! 📝&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The resource server now handles step-up authentication for the "messages" route. It returns the standard error when user authentication is insufficient, but the Angular frontend needs to respond to this error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use an Angular interceptor to catch step-up HTTP error responses &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In Angular, we'll first identify the step-up authentication error response, then manipulate the HTTP error response by extracting the information needed for further handling. It starts in an interceptor.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;packages/frontend-angular/src/app/stepup.interceptor.ts&lt;/code&gt;, an unmodified interceptor file scaffolded by Angular CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;HttpInterceptorFn&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="s1"&gt;@angular/common/http&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;stepupInterceptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpInterceptorFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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;Intercepting and handling HTTP error responses means we'll catch the error and provide an error handler function. Change your code as shown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;HttpErrorResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HttpInterceptorFn&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="s1"&gt;@angular/common/http&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;catchError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;throwError&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="s1"&gt;rxjs&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;handleError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;httpError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpErrorResponse&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;return&lt;/span&gt; &lt;span class="nf"&gt;throwError&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;httpError&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;const&lt;/span&gt; &lt;span class="nx"&gt;stepupInterceptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpInterceptorFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleError&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 error handler needs first to verify this is an error we want to handle. Is this HTTP error a step-up error from our resource server? We can check for this! In the &lt;code&gt;handleError&lt;/code&gt; method, add the following code and change the return value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;httpError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpErrorResponse&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;allowedOrigins&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="s1"&gt;/api&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;httpError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Unauthorized&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;allowedOrigins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&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;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;httpError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;includes&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;throwError&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;httpError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;returnError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpErrorResponse&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;acr_values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;httpError&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;authResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;httpError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WWW-Authenticate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&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="nx"&gt;authResponse&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="nf"&gt;throwError&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;returnError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// add code to extract error details and format new error type&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;throwError&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;returnError&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;Now we're at the stage where we know this is most likely an error we should handle, and we'll know for sure by extracting the &lt;code&gt;insuffcient_user_authentication&lt;/code&gt; string from the &lt;code&gt;WWW-Authenticate&lt;/code&gt; header. While parsing the header string, we'll look for the &lt;code&gt;acr_values&lt;/code&gt;. Add the code to support this by replacing the &lt;code&gt;// add code to extract error details and format new error type&lt;/code&gt; with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;acr_values&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;authResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bearer &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="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"&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="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;=&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;insufficient_user_authentication&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="nx"&gt;returnError&lt;/span&gt; &lt;span class="o"&gt;=&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;acr_values&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;Lastly, add the interceptor to the &lt;code&gt;ApplicationConfig&lt;/code&gt;. Open &lt;code&gt;packages/frontend-angular/src/app/app.config.ts&lt;/code&gt;. Add the &lt;code&gt;stepupInterceptor&lt;/code&gt; to the providers array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;provideHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;withInterceptors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="nx"&gt;authInterceptor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;stepupInterceptor&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can't redirect the user to authentication from an interceptor. You need to handle this new error format elsewhere, where you initiate redirecting the user to authentication with the required &lt;code&gt;acr_values&lt;/code&gt; before re-requesting the resource.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handle step-up errors when making HTTP calls in Angular &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;You can handle catching the error, redirecting the user to authenticate, and re-request the resource within the call to the API, usually within an Angular service. I cheated a bit and wrote the API call directly in the component in this demonstration. Open &lt;code&gt;packages/frontend-angular/src/app/messages/messages.component.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You need the Angular &lt;code&gt;Router&lt;/code&gt; and &lt;code&gt;OKTA_AUTH&lt;/code&gt; instances so you can save the existing URL then redirect the user to authenticate. Create properties and inject both types within the class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;oktaAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OKTA_AUTH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;messages$&lt;/code&gt; to add a &lt;code&gt;catchError&lt;/code&gt; operator. Within the &lt;code&gt;catchError&lt;/code&gt; function, you'll ensure the error type is &lt;code&gt;insufficient_user_authentication&lt;/code&gt;, set the redirect URI to navigate the user back to this component which will re-request the resource, and finally redirect the user to authenticate using the &lt;code&gt;acr_values&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;messages$&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;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Message&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]),&lt;/span&gt;
    &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;insufficient_user_authentication&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;acrValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;acr_values&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;redirectTo&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routerState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOriginalUri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redirectTo&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;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signInWithRedirect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;acrValues&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="nf"&gt;throwError&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code sure looks similar to the operations in the step-up auth Angular guard! &lt;/p&gt;

&lt;p&gt;Try out your work. Ensure you sign out of the application first. Sign in with one factor, then navigate to the "messages" route. You'll redirect to sign in with a second factor. Success!&lt;/p&gt;

&lt;h2&gt;
  
  
  Ensure authentication recency in step-up authentication &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We covered the authentication levels in this post because they are visually visible within the Okta-hosted sign-in page. The step-up authentication challenge protocol also supports authentication recency. The good news is the code and process we covered in the post still apply, but you'll use different claims and properties. In the redirect request, you'll define the required business rules for authentication recency using the &lt;code&gt;max_age&lt;/code&gt; property instead of &lt;code&gt;acr_values&lt;/code&gt;. Calculate authentication recency using the &lt;code&gt;auth_time&lt;/code&gt; claim when evaluating whether a token meets the &lt;code&gt;max_age&lt;/code&gt; requirement. Cool stuff indeed!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-up authentication in Angular and NestJS applications &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In this post, you walked through adding a step-up authentication challenge to protect resources. You added step-up authentication to protect Angular routes using the Okta Angular SDK, then added step-up authentication to protect resources from the NestJS API and within the Angular app.&lt;/p&gt;

&lt;p&gt;There's a lot more we can do, and in a demo, we can't get into all the production-level polish we'd like, but I hope this sparks your imagination about how you can protect resources within your application. You can check out the completed application in the &lt;code&gt;completed&lt;/code&gt; branch of the &lt;a href="https://github.com/oktadev/okta-angular-nestjs-stepup-auth-example/tree/completed" rel="noopener noreferrer"&gt;okta-angular-nestjs-stepup-auth-example&lt;/a&gt; GitHub repository. The repository's README also includes instructions on scaffolding the starting project.&lt;/p&gt;

&lt;p&gt;Ready to read other interesting posts? Check out the following links.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2023/03/08/step-up-auth" rel="noopener noreferrer"&gt;Step-up Authentication in Modern Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2023/10/24/stepup-okta" rel="noopener noreferrer"&gt;Step-Up Authentication Examples With Okta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2024/02/28/okta-authentication-angular" rel="noopener noreferrer"&gt;Flexible Authentication Configurations in Angular Applications Using Okta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2024/02/28/okta-authentication-angular" rel="noopener noreferrer"&gt;How to Build Micro Frontends Using Module Federation in Angular&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and subscribe to our &lt;a href="https://www.youtube.com/c/OktaDev/" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for more exciting content. We also want to hear about the tutorials you want to see. Leave us a comment below!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>authentication</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Flexible Authentication Configurations in Angular Applications Using Okta</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Tue, 12 Mar 2024 16:17:17 +0000</pubDate>
      <link>https://forem.com/oktadev/flexible-authentication-configurations-in-angular-applications-using-okta-5c7e</link>
      <guid>https://forem.com/oktadev/flexible-authentication-configurations-in-angular-applications-using-okta-5c7e</guid>
      <description>&lt;p&gt;Are you ready to hear about the ultimate flexibility in configuring authentication properties in the Okta Angular SDK? You'll want to check out this excellent new feature and walk through the steps of adding authentication using Okta to Angular applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring authentication properties using Okta in Angular applications &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;There are three main ways you can add configuration information to Angular applications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define the value within the app&lt;/strong&gt; - The easiest, most straightforward route is directly defining the configuration within the &lt;code&gt;AppModule&lt;/code&gt; or &lt;code&gt;app.config.ts&lt;/code&gt;. Sure, it's direct, but it can be limiting since the value can always stay the same.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add it into &lt;code&gt;env&lt;/code&gt; files&lt;/strong&gt; - You can take the configuration definitions out of the application and pull the values during build time. But this means you'll need to build separate applications for each environment requiring unique configs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Populate configuration at runtime&lt;/strong&gt; - In this pattern, you'd retrieve the configuration in an HTTP call from an API when the app starts and populate the configuration values upon receiving the HTTP response. Runtime configuration means you can change the config values without building and redeploying the Angular application! It's the ultimate flexibility and the awesome new feature I hinted at in the Okta Angular SDK!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;💡 You can read more about these three ways, along with examples, in &lt;a href="https://developer.okta.com/blog/2022/02/24/angular-async-config" rel="noopener noreferrer"&gt;Three Ways to Configure Modules in Your Angular App&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The best way to experiment with loading authentication configuration at runtime is to try it out yourself. Pull out your machine and warm up your fingers! If you want to jump to the completed project, you can find it in the &lt;a href="https://github.com/oktadev/okta-angular-standalone-runtime-config-example" rel="noopener noreferrer"&gt;okta-angular-standalone-config-example&lt;/a&gt; GitHub repository.&lt;/p&gt;

&lt;p&gt;Otherwise, let's get coding! &lt;/p&gt;

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

&lt;p&gt;This post is best for developers familiar with Angular. If you are an Angular newbie, start by building &lt;a href="https://angular.io/tutorial/first-app" rel="noopener noreferrer"&gt;your first Angular app&lt;/a&gt; using the tutorial created by the Angular team.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For this tutorial, you will need the following tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; v18 or greater&lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular.io/cli" rel="noopener noreferrer"&gt;Angular CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A web browser with good debugging capabilities&lt;/li&gt;
&lt;li&gt;Your favorite IDE. Still on the hunt? I like VS Code and WebStorm because they have integrated terminal windows.&lt;/li&gt;
&lt;li&gt;Terminal window (if you aren't using an IDE with a built-in terminal)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuring authentication properties using Okta in Angular applications&lt;/li&gt;
&lt;li&gt;Scaffold an Angular standalone application&lt;/li&gt;
&lt;li&gt;Create an Okta OAuth 2.0 and OpenID Connect SPA client&lt;/li&gt;
&lt;li&gt;Use the Okta Angular SDK for authentication&lt;/li&gt;
&lt;li&gt;Display OpenID Connect claims&lt;/li&gt;
&lt;li&gt;Intercept HTTP requests to add the Authorization header with a functional interceptor&lt;/li&gt;
&lt;li&gt;Add runtime authentication configuration to an Okta Angular app&lt;/li&gt;
&lt;li&gt;Use OAuth 2.0, OpenID Connect, and the Okta Angular SDK for secure authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scaffold an Angular standalone application &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Angular introduced standalone components as a developer preview in v14. Since then, the Angular team continued building support for the architecture. It's now the default when using the Angular CLI in v17, so we'll use standalone components, functional interceptors, and control flow in this sample. &lt;/p&gt;

&lt;p&gt;In the terminal, run the following commands to generate the app and add the components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;npx @angular/cli@17 new okta-angular-example --routing --style scss --defaults
cd okta-angular-example
ng generate component profile --inline-template --inline-style
ng generate component protected --inline-template --inline-style
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Open the &lt;code&gt;okta-angular-example&lt;/code&gt; project in your IDE. You'll first define all the routes for the project. Open the &lt;code&gt;protected&lt;/code&gt; folder and add &lt;code&gt;routes.ts&lt;/code&gt;. We will treat this component as an entrance to a lazy-loaded route. Add the following code to the &lt;code&gt;routes.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Route&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="s1"&gt;@angular/router&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;ProtectedComponent&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="s1"&gt;./protected.component&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;PROTECTED_FEATURE_ROUTES&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="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProtectedComponent&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;Open &lt;code&gt;app.routes.ts&lt;/code&gt;. Add the following routes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Routes&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="s1"&gt;@angular/router&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;ProfileComponent&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="s1"&gt;./profile/profile.component&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;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProfileComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;protected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./protected/routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PROTECTED_FEATURE_ROUTES&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;There's more to do here, but we'll add it after you add Okta to the project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Create an Okta OAuth 2.0 and OpenID Connect SPA client &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You'll use Okta to securely handle authentication and authorization for your Angular application.&lt;/p&gt;

&lt;p&gt;Before you begin, you’ll need a free Okta developer account. Install the &lt;a href="https://cli.okta.com/" rel="noopener noreferrer"&gt;Okta CLI&lt;/a&gt; and run &lt;code&gt;okta register&lt;/code&gt; to sign up for a new account. If you already have an account, run &lt;code&gt;okta login&lt;/code&gt;. Then, run &lt;code&gt;okta apps create&lt;/code&gt;. Select the default app name, or change it as you see fit. Choose &lt;strong&gt;Single-Page App&lt;/strong&gt; and press &lt;strong&gt;Enter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Use &lt;a href="http://localhost:4200/login/callback" rel="noopener noreferrer"&gt;http://localhost:4200/login/callback&lt;/a&gt; for the Redirect URI and set the Logout Redirect URI to &lt;a href="http://localhost:4200" rel="noopener noreferrer"&gt;http://localhost:4200&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
  What does the Okta CLI do?
  &lt;br&gt;
The Okta CLI will create an OIDC Single-Page App in your Okta Org. It will add the redirect URIs you specified and grant access to the Everyone group. It will also add a trusted origin for &lt;code&gt;http://localhost:4200&lt;/code&gt;. You will see output like the following when it’s finished:&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Okta application configuration:
Issuer:    https://dev-133337.okta.com/oauth2/default
Client ID: 0oab8eb55Kb9jdMIr5d6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: You can also use the Okta Admin Console to create your app. See &lt;a href="https://developer.okta.com/docs/guides/sign-into-spa/angular/create-okta-application/" rel="noopener noreferrer"&gt;Create an Angular App&lt;/a&gt; for more information.&lt;br&gt;
&lt;/p&gt;

&lt;/p&gt;

&lt;p&gt;Note the &lt;code&gt;Issuer&lt;/code&gt; and the &lt;code&gt;Client ID&lt;/code&gt;. You'll need those values for your authentication configuration coming up soon.&lt;/p&gt;

&lt;p&gt;There's one manual change to make in the Okta Admin Console. Add the &lt;strong&gt;Refresh Token&lt;/strong&gt; grant type to your Okta Application. Open a browser tab to sign in to your &lt;a href="https://developer.okta.com/login/" rel="noopener noreferrer"&gt;Okta developer account&lt;/a&gt;. Navigate to &lt;strong&gt;Applications&lt;/strong&gt; &amp;gt; &lt;strong&gt;Applications&lt;/strong&gt; and find the Okta Application you created. For Okta Applications using the default name, find the Application named "My SPA." Otherwise find the Application with your custom name. Select the name to edit the application. Find &lt;strong&gt;General Settings&lt;/strong&gt; section and press the &lt;strong&gt;Edit&lt;/strong&gt; button to add a Grant type. Activate the &lt;strong&gt;Refresh Token&lt;/strong&gt; checkbox and press &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We'll use the &lt;a href="https://www.npmjs.com/package/@okta/okta-angular" rel="noopener noreferrer"&gt;Okta Angular&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/@okta/okta-auth-js" rel="noopener noreferrer"&gt;Okta Auth JS&lt;/a&gt; libraries to connect our Angular application with Okta authentication. Add them to your project by running the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @okta/okta-angular@6.3 @okta/okta-auth-js@7.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Use the Okta Angular SDK for authentication &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You'll start by directly adding the Okta configuration to the application, which is the first and most straightforward method of adding configuration to Angular applications. Open &lt;code&gt;app.config.ts&lt;/code&gt;, and make the following modifications to import the &lt;code&gt;OktaAuthModule&lt;/code&gt; and define the configuration:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;OktaAuthModule&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="s1"&gt;@okta/okta-angular&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;OktaAuth&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="s1"&gt;@okta/okta-auth-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;appConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&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="nf"&gt;importProvidersFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;OktaAuthModule&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="na"&gt;oktaAuth&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;OktaAuth&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://{yourOktaDomain}/oauth2/default&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="s1"&gt;{yourClientId}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;redirectUri&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;/login/callback`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;scopes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openid&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="s1"&gt;offline_access&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="s1"&gt;profile&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;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routes&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;Don't forget to replace &lt;code&gt;{yourOktaDomain}&lt;/code&gt; and &lt;code&gt;{yourClientId}&lt;/code&gt; with the values you got from the Okta CLI!&lt;/p&gt;

&lt;p&gt;With Okta added to the project, let's return to the route definitions. You can define the sign-in redirect route and add guards to those routes. Open &lt;code&gt;app.routes.ts&lt;/code&gt; and make the changes so that your route definitions look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Routes&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="s1"&gt;@angular/router&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;OktaAuthGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OktaCallbackComponent&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="s1"&gt;@okta/okta-angular&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;ProfileComponent&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="s1"&gt;./profile/profile.component&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;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProfileComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OktaAuthGuard&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;protected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./protected/routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PROTECTED_FEATURE_ROUTES&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OktaAuthGuard&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OktaCallbackComponent&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;You'll add the code for the components using the Okta SDK to sign in, sign out, and display user claims. We'll keep the components and their styles minimal so we can focus on the authentication pieces.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;app.component.html&lt;/code&gt;. Copy the following code into the file.&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;class=&lt;/span&gt;&lt;span class="s"&gt;"toolbar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  @if (isAuthenticated$ | async) {
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"routes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/profile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Profile&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/protected"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Protected&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/nav&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;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth"&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;/a&amp;gt;&lt;/span&gt;
  } @else {
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth"&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;/a&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;p&amp;gt;&lt;/span&gt;Learn more about Okta at &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://developer.okta.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;developer.okta.com&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the &lt;code&gt;app.component.scss&lt;/code&gt;, copy the following code and paste it into the file. No frills here! We are keeping this focused on function, not form. 😅&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nd"&gt;:host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nd"&gt;:visited&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#095661&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.toolbar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.routes&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.routes&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.auth&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="mh"&gt;#999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#2d8c9e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#fff&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="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;large&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;Finally, we can get to the interesting authentication components. Open &lt;code&gt;app.component.ts&lt;/code&gt;. Since this is a standalone component, you must import the classes it relies on, &lt;code&gt;AsyncPipe&lt;/code&gt;, &lt;code&gt;RouterOutlet&lt;/code&gt;, and &lt;code&gt;RouterLink&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You'll use two classes and libraries from Okta, so inject the &lt;code&gt;OktaAuthStateService&lt;/code&gt; and &lt;code&gt;OKTA_AUTH&lt;/code&gt; injection tokens. The &lt;code&gt;OktaAuthStateService.authState$&lt;/code&gt; observable stream emits an authenticated state. You can use this to watch for whether you show the sign-in or sign-out buttons and add the functionality to sign in and sign out using Okta:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;AsyncPipe&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="s1"&gt;@angular/common&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;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&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="s1"&gt;@angular/core&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;RouterLink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RouterOutlet&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="s1"&gt;@angular/router&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;OktaAuthStateService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OKTA_AUTH&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="s1"&gt;@okta/okta-angular&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;AuthState&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="s1"&gt;@okta/okta-auth-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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&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="s1"&gt;rxjs&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&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;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;AsyncPipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RouterOutlet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RouterLink&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.scss&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;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;oktaStateService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OktaAuthStateService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;oktaAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OKTA_AUTH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;isAuthenticated$&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;oktaStateService&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&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;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&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;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&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;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;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signInWithRedirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&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;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;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signOut&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;This code gets you authenticated using Okta. Feel free to start the application and verify you can sign in and out. Serve the application by running the following command in your terminal:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;npm start
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;If you have app initialization errors, double-check your Okta configuration and replace the placeholders.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You should see something like this when you start the application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F472mmtfji2nmifc9oger.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F472mmtfji2nmifc9oger.jpg" alt="The application start screen shows a sign in button and a link to the Okta Developer site" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The links for the profile and protected routes display after you sign in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fglhiwdtnabqnaglf1eai.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fglhiwdtnabqnaglf1eai.jpg" alt="The application after authenticating showing a sign out button, links to profile and protected routes, and a link to the Okta Developer site" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I made no claims about building a &lt;em&gt;beautiful&lt;/em&gt; app. &lt;/p&gt;

&lt;p&gt;The profile and protected routes display the default text from Angular CLI. It's time to add something a little more interesting!&lt;/p&gt;
&lt;h2&gt;
  
  
  Display OpenID Connect claims &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The profile should display something about the profile! So, let's add the code to read one of your standard ID claims and display a warm, friendly greeting to the signed-in user. Open &lt;code&gt;profile.component.ts&lt;/code&gt;. This component uses an inline template and styles.&lt;/p&gt;

&lt;p&gt;You'll add the &lt;code&gt;AsyncPipe&lt;/code&gt; to the imports array and the following template code, replacing the existing template:&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;p&amp;gt;&lt;/span&gt;You're logged in!
  @if(name$ | async; as name) {
    &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Welcome, {{name}} &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  }
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Time to pretty up the template. Check out the styles, and add this stylistic marvel into the component declaration for the inline styles. Feel free to add some extra flair if you'd like and make this project your own. 🎉&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&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;To display the claim value, you'll use the &lt;code&gt;OktaAuthStateService&lt;/code&gt;, which holds your ID token and already decodes the payload for you. That's pretty handy! You'll pipe the &lt;code&gt;authState$&lt;/code&gt; observable stream to filter out unauthenticated state and then use the &lt;code&gt;name&lt;/code&gt; claim property. Your component code will look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;ProfileComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;oktaAuthStateService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OktaAuthStateService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;name$&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;oktaAuthStateService&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;filter&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;AuthState&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;!!&lt;/span&gt;&lt;span class="nx"&gt;authState&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;authState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;map&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;AuthState&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;authState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;idToken&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When you sign in and navigate to the profile route, you'll see something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fis4v9s6sbmjidds00fm1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fis4v9s6sbmjidds00fm1.jpg" alt="The application profile route displaying a welcome message with the user's name" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this, you should now have a working app that allows you to sign in, navigate to protected to see there's nothing there, navigate to profile and feel welcomed, and lastly sign out. Most applications with authentication need an interceptor to add the &lt;code&gt;Authorization&lt;/code&gt; header. Even though we aren't calling an API, let's put it in to walk through the steps.&lt;/p&gt;
&lt;h2&gt;
  
  
  Intercept HTTP requests to add the Authorization header with a functional interceptor &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Interceptors manipulate outgoing and incoming HTTP requests, and it's a fantastic way to automatically add the &lt;code&gt;Authorization&lt;/code&gt; header along with the access token to outgoing calls!&lt;/p&gt;

&lt;p&gt;In a new terminal, use Angular CLI to scaffold an interceptor using the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;ng generate interceptor auth
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Open the &lt;code&gt;auth.interceptor.ts&lt;/code&gt; file to make the required changes. You'll see Angular CLI created the interceptor function. The &lt;code&gt;Authorization&lt;/code&gt; header contains highly sensitive information, the access token! &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tr&gt;
    &lt;td&gt;⚠️&lt;/td&gt;
    &lt;td&gt;
      **Heads up!** &lt;br&gt;
      The access token grants the caller permission to access resources, perform actions, and potentially make devastating changes in the name of the user to whom the access token belongs. You don't want the token to fall into the wrong hands!
    &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In other words, we must protect the token by sending the token to allowed origins. Change the interceptor code to look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;HttpInterceptorFn&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="s1"&gt;@angular/common/http&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;inject&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="s1"&gt;@angular/core&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;OKTA_AUTH&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="s1"&gt;@okta/okta-angular&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;authInterceptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpInterceptorFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oktaAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OKTA_AUTH&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;let&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&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;allowedOrigins&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="s1"&gt;/api&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;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAccessToken&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;accessToken&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;allowedOrigins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&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;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;setHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accessToken&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&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;You've completed the interceptor code, but you have to register the interceptor in the application and bring in the HTTP libraries. Open &lt;code&gt;app.config.ts&lt;/code&gt; and add the following code to the &lt;code&gt;providers&lt;/code&gt; array after the &lt;code&gt;provideRouter(routes)&lt;/code&gt; line:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;provideHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;withInterceptors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="nx"&gt;authInterceptor&lt;/span&gt;
&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When you make HTTP calls to allowed origins, you'll now see the access token in the header. Feel free to try this out on your own by calling an API such as this &lt;a href="https://github.com/okta/samples-nodejs-express-4/tree/master/resource-server" rel="noopener noreferrer"&gt;sample Express API from Okta&lt;/a&gt;, which verifies the access token, too. &lt;/p&gt;

&lt;p&gt;We've done a lot, but the application still contains the hard-coded Okta configuration. What if you want to load the configuration at runtime from an external source? We can emulate this process!&lt;/p&gt;
&lt;h2&gt;
  
  
  Add runtime authentication configuration to an Okta Angular app &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Stop the application by typing &lt;code&gt;ctrl+c&lt;/code&gt; in the command line. You'll change the &lt;code&gt;angular.json&lt;/code&gt; file, which requires a restart of the application. &lt;/p&gt;

&lt;p&gt;Emulate the response from calling an external API by creating a folder called &lt;code&gt;api&lt;/code&gt; inside the existing &lt;code&gt;src&lt;/code&gt; folder. Then, create a file called &lt;code&gt;config.json&lt;/code&gt; within the &lt;code&gt;api&lt;/code&gt; folder. Your project file structure will look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;okta-angular-example
├── src
│   ├── api
│   │   └── config.json
│   ├── app
│   │   └── all the components
│   └── assets, remaining files
└── remaining files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Open &lt;code&gt;config.json&lt;/code&gt; and add the following JSON properties. We'll use this format for the configuration response you get from calling an external API:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"issuer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://{yourOktaDomain}.okta.com/oauth2/default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"clientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{yourClientId}"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Hey! Those properties and variables look familiar, right? Replace the variables to match what you got from the Okta CLI and what you have in the &lt;code&gt;app.config.ts&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The Angular project doesn't recognize this API path and config file, so if you try serving the application right now, the &lt;code&gt;ng serve&lt;/code&gt; process won't serve the &lt;code&gt;config.json&lt;/code&gt; file with the app. We must also configure the serve process to include the &lt;code&gt;api&lt;/code&gt; folder. Open &lt;code&gt;angular.json&lt;/code&gt; and find the &lt;code&gt;projects.okta-angular-example.architect.build&lt;/code&gt; section. Add &lt;code&gt;src/api&lt;/code&gt; to the list of assets in the build option:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"src/favicon.ico"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"src/assets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"src/api"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can now access the &lt;code&gt;config.json&lt;/code&gt; file at runtime. Feel free to start the application again using &lt;code&gt;npm start&lt;/code&gt; in the terminal. In the browser, navigate to &lt;code&gt;http://localhost:4200/api/config.json&lt;/code&gt;. This route is accessible by your application, and we'll mimic an HTTP call to read the configuration at runtime.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;app.config.ts&lt;/code&gt;. Add a function before the &lt;code&gt;export const appConfig&lt;/code&gt; to call the config endpoint for the configuration as shown:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;configInitializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;httpBackend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpBackend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OktaAuthConfigService&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;void&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="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;httpBackend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api/config.json&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;authConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&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="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;oktaAuth&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;OktaAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;authConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;redirectUri&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;/login/callback`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;scopes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openid&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="s1"&gt;offline_access&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="s1"&gt;profile&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;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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;Let's talk through the code. The function takes two parameters - the &lt;code&gt;HttpBackend&lt;/code&gt; class and the &lt;code&gt;OktaAuthConfigService&lt;/code&gt; classes. You first create a new &lt;code&gt;HttpClient&lt;/code&gt;. Notice we're not using the &lt;code&gt;HttpClient&lt;/code&gt; we can get from Angular dependency injection. We want our auth interceptor to skip &lt;em&gt;this&lt;/em&gt; HTTP call. Once you get the &lt;code&gt;config.json&lt;/code&gt; response, you set the &lt;code&gt;OktaAuthConfigService&lt;/code&gt; with those properties.&lt;/p&gt;

&lt;p&gt;Next, you can change the &lt;code&gt;ApplicationConfig&lt;/code&gt;, by removing the configuration from the &lt;code&gt;OktaAuthModule&lt;/code&gt; by deleting the &lt;code&gt;.forRoot&lt;/code&gt; method call. You also need this function to run when the application starts. The &lt;code&gt;APP_INITIALIZER&lt;/code&gt; injection token exists precisely for this need. Provide the &lt;code&gt;APP_INITIALIZER&lt;/code&gt; injection token with the &lt;code&gt;configInitializer&lt;/code&gt; function and the necessary dependencies, and add it to the providers array. The &lt;code&gt;appConfig&lt;/code&gt; now looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;appConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&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="nf"&gt;importProvidersFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;OktaAuthModule&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;provideHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;withInterceptors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="nx"&gt;authInterceptor&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;configInitializer&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;HttpBackend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OktaAuthConfigService&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Check it out to verify you can sign in, greet yourself at the profile route, and sign out. Success!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What if you use NgModules architecture?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While this sample demonstrates how to add runtime configuration loading in a standalone application, you can use the same steps in an Angular application with NgModule architecture. Instead, you'll provide the &lt;code&gt;APP_INITIALIZER&lt;/code&gt; in the &lt;code&gt;AppModule&lt;/code&gt; providers array.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Use OAuth 2.0, OpenID Connect, and the Okta Angular SDK for secure authentication &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In this post, you added runtime Okta configuration in an Angular app using standalone components. Whew! That was a lot of work, but I hope you found it fun and exciting. You can check out the completed application in the &lt;a href="https://github.com/oktadev/okta-angular-standalone-runtime-config-example" rel="noopener noreferrer"&gt;okta-angular-standalone-runtime-config-example&lt;/a&gt; GitHub repository.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/oktadev" rel="noopener noreferrer"&gt;
        oktadev
      &lt;/a&gt; / &lt;a href="https://github.com/oktadev/okta-angular-standalone-runtime-config-example" rel="noopener noreferrer"&gt;
        okta-angular-standalone-runtime-config-example
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Use Okta Angular SDK for runtime configuration loading in standalone Angular applications
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Angular Standalone Runtime Configuration Example&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This repository contains a working example of adding Okta Angular SDK to a standalone Angular project and how to load the Okta authentication configuration at runtime. Please read &lt;a href="https://developer.okta.com/blog/2024/02/28/okta-authentication-angular" rel="nofollow noopener noreferrer"&gt;Flexible Authentication Configurations in Angular Applications Using Okta&lt;/a&gt; for a detailed guide through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node 18 or greater&lt;/li&gt;
&lt;li&gt;Okta CLI&lt;/li&gt;
&lt;li&gt;Angular CLI&lt;/li&gt;
&lt;li&gt;Your favorite IDE&lt;/li&gt;
&lt;li&gt;A web browser with good debugging capabilities&lt;/li&gt;
&lt;li&gt;Terminal window&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://developer.okta.com/" rel="nofollow noopener noreferrer"&gt;Okta&lt;/a&gt; has Authentication and User Management APIs that reduce development time with instant-on, scalable user infrastructure. Okta's intuitive API and expert support make it easy for developers to authenticate, manage and secure users and roles in any application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-standalone-runtime-config-example#getting-started" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-standalone-runtime-config-example#links" rel="noopener noreferrer"&gt;Links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-standalone-runtime-config-example#help" rel="noopener noreferrer"&gt;Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-standalone-runtime-config-example#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;To run this example, run the following commands:&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/oktadev/okta-angular-standalone-runtime-config-example.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; okta-angular-standalone-runtime-config-example
npm ci&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Create an OIDC Application in Okta&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;Create a free developer account with the following command using the &lt;a href="https://cli.okta.com" rel="nofollow noopener noreferrer"&gt;Okta CLI&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;okta register&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/oktadev/okta-angular-standalone-runtime-config-example" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Complete code projects include testing. I didn't walk through the steps of adding unit tests in this post, but you can inspect the completed code project to view and run the tests, too.&lt;/p&gt;

&lt;p&gt;Ready to read other interesting posts? Check out the following links.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/10/11/angular-dependency-injection" rel="noopener noreferrer"&gt;Practical Uses of Dependency Injection in Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2021/12/08/angular-dynamic-loading" rel="noopener noreferrer"&gt;Loading Components Dynamically in an Angular App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/05/17/angular-microfrontend-auth" rel="noopener noreferrer"&gt;How to Build Micro Frontends Using Module Federation in Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/07/06/spa-web-security" rel="noopener noreferrer"&gt;Defend Your SPA from Security Woes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2023/03/07/angular-forroot" rel="noopener noreferrer"&gt;Streamline Your Okta Configuration in Angular Apps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and subscribe to our &lt;a href="https://www.youtube.com/c/OktaDev/" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for more exciting content. We also want to hear about what tutorials you want to see. Leave us a comment below!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>okta</category>
    </item>
    <item>
      <title>How Authentication and Authorization Work for SPAs</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Wed, 12 Apr 2023 15:02:01 +0000</pubDate>
      <link>https://forem.com/oktadev/how-authentication-and-authorization-work-for-spas-1e4h</link>
      <guid>https://forem.com/oktadev/how-authentication-and-authorization-work-for-spas-1e4h</guid>
      <description>&lt;p&gt;Adding authentication to public clients such as Single Page Applications (SPA) and JavaScript applications can be a source of confusion. Identity Providers like Okta try to help you via multiple support systems. Still, it can feel like a lot of work. Especially since you’re responsible for way more than authentication alone in the applications you work on!&lt;/p&gt;

&lt;p&gt;As part of authentication, your client application makes multiple calls to an authorization server, and you get back several strings, which are tokens. Let’s demystify what’s going on behind the scenes and closely examine what those tokens are and how you use them within your client application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication and Authorization using OAuth 2.0 + OpenID Connect (OIDC)&lt;/li&gt;
&lt;li&gt;OAuth 2.0 + OIDC for JavaScript clients and SPA&lt;/li&gt;
&lt;li&gt;
Auth tokens in OAuth 2.0 + OIDC

&lt;ul&gt;
&lt;li&gt;ID token&lt;/li&gt;
&lt;li&gt;Access token&lt;/li&gt;
&lt;li&gt;Refresh token&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Create an OAuth 2.0 + OIDC Compliant Authorization server&lt;/li&gt;

&lt;li&gt;View the well-known endpoint for OIDC Discovery&lt;/li&gt;

&lt;li&gt;Debug the authorization code and token requests&lt;/li&gt;

&lt;li&gt;Add authentication to your SPA&lt;/li&gt;

&lt;li&gt;

&lt;a href=""&gt;Use auth tokens in SPAs&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=""&gt;How to use the access token&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=""&gt;How to use the ID token&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Learn more about OAuth, OIDC, tokens, and authentication best practices&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;There’s a &lt;a href="https://youtu.be/UZQ_ke8BuRU" rel="noopener noreferrer"&gt;companion video for this post&lt;/a&gt; if you want to check out how to run a SPA sample application, look at browser storage, and inspect network calls.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/UZQ_ke8BuRU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication and Authorization using OAuth 2.0 + OpenID Connect (OIDC) &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;OAuth 2.0 with OIDC is the best practice for adding authentication and authorization to your software applications. Authentication verifies the identity of who you claim to be, and authorization verifies you have access to data you want to see or actions you want to perform. It is lightweight with less effort to set up and use than Security Assertion Markup Language (SAML), an alternate authentication and authorization mechanism that pre-existing systems may use. For newer systems, you’ll want to use OAuth 2.0 + OIDC.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F87c48dveei580ymtvruq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F87c48dveei580ymtvruq.jpg" alt="OAuth and OIDC logos" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OAuth 2.0 handles authorization to resources, such as when your front-end application gets data from a backend API by making an HTTP request. OAuth 2.0 standards have the flexibility to support authorization across your entire application system through different flows and grant types. For example, different OAuth 2.0 flows support JavaScript-based front-end applications, for your APIs and back-end services to communicate, and even for IOT devices in your home automation system. OpenID Connect (OIDC) is an identity layer on OAuth 2.0 that provides standardized identity information.&lt;/p&gt;

&lt;h2&gt;
  
  
  OAuth 2.0 + OIDC for JavaScript clients and SPA &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;SPAs and other JavaScript front-ends are public clients, which means they can’t maintain secret information for authorization, unlike a confidential client. A confidential client (such as a traditional server-rendered web app) can keep super secret information such as a Client Secret for authorization. In both application types, we should use a flow called Authorization Code and an extension to the flow called Proof Key for Code Exchange (PKCE).&lt;/p&gt;

&lt;p&gt;Let’s see how this flow works step-by-step following what happens when a cute dinosaur named Sunny prepares to sign in to the “Rawr” app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Frnm07ahe73kdcoxpggw4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Frnm07ahe73kdcoxpggw4.jpg" alt="Sunny, a cute smiley dinosaur, is ready to sign in to the Rawr app" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The client application starts the process and generates a random, long string — the code verifier. Then it creates a code challenge from the code verifier. This step is part of the PKCE extension.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fekipe1on3miezn8zj70f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fekipe1on3miezn8zj70f.jpg" alt="The client application processing the sign-in to create a code verifier and code challenge" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The client application holds on to the code verifier. It then makes an authorization code request to your authorization server, in this case, represented by Okta. The authorization code request includes the code challenge along with some critical pieces of information, such as&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client ID&lt;/li&gt;
&lt;li&gt;Scopes, including at least the following:

&lt;ul&gt;
&lt;li&gt; &lt;code&gt;openid&lt;/code&gt; required for specifying the app uses OIDC in verifying the user's identity&lt;/li&gt;
&lt;li&gt; &lt;code&gt;profile&lt;/code&gt; for accessing the user's profile information, such as their name&lt;/li&gt;
&lt;li&gt; &lt;code&gt;offline_access&lt;/code&gt; to request a Refresh Token as part of this call&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Redirect URI for the callback location within the client application when sign-in is complete&lt;/li&gt;

&lt;li&gt;A random alphanumeric string for preventing Cross-Site Request Forgery (CSRF)&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fgna1w6e5lsuq3d48dnzt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fgna1w6e5lsuq3d48dnzt.jpg" alt="The client application making an authorization code request to the authorization server, Okta, with the information mentioned above" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The authorization server redirects the user, Sunny, to a web page it hosts to sign in and provide authorization consent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fhv0igl460f55gg1fgnut.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fhv0igl460f55gg1fgnut.jpg" alt="The client application redirects to Okta hosted sign-in screen, and Sunny authenticates and grant consent" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yay! Sign-in success! The authorization server returns an authorization code to the client application. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F1cpgnhqf0b8y9p89vfb5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F1cpgnhqf0b8y9p89vfb5.jpg" alt="The authorization server redirects back to the client application and returns an authorization code" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that there's an authorization code, the client application makes a request to the token endpoint of the authorization server and sends the authorization code and the code verifier. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F47j6b1twyjmjwid7kek9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F47j6b1twyjmjwid7kek9.jpg" alt="The client making a token request and sending the information listed above in the payload" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To process the token endpoint request the authorization server ensures the authorization code is still valid and that the code verifier matches the code challenge sent in the authorization request. This step is part of the PKCE extension.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fnmkkduqyglvf4i3srjg4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fnmkkduqyglvf4i3srjg4.jpg" alt="The authorization server verifying the authorization code and the code verifier" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yay! Success! The authorization server returns three tokens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Access token&lt;/li&gt;
&lt;li&gt;ID token&lt;/li&gt;
&lt;li&gt;Refresh token&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F92i2u6xks3gfyeu0ntds.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F92i2u6xks3gfyeu0ntds.jpg" alt="The authorization server responds to the token request with three tokens" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that Sunny successfully signed in, they can continue their rawring lessons!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F8atojoih7jwriqnsvzp9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F8atojoih7jwriqnsvzp9.jpg" alt="A happy dinosaur getting ready to start a lesson in how to rawr" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you have these three tokens let's better understand what each one is for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth tokens in OAuth 2.0 + OIDC &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;These three tokens provide crucial information about your identity, access to resources, and the ability to stay authenticated securely.&lt;/p&gt;

&lt;h3&gt;
  
  
  ID token &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The ID token is about the user, so information about Sunny in this case. This authentication token is returned from the OpenID Connect layer. It contains standardized identity information such as email, name, and issuing party, called claims. The ID token may include extra claims for information critical to Sunny's identity, such as their dinosaur family, which is a Smileasaur of course.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access token &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The access token is a key that grants access to data or to perform an action. This authorization token is returned from the OAuth layer. The token has metadata about the token itself, such as the issuing party, information about requested scopes made in the original request, and the expiration time. Access tokens are intentionally short-lived for public clients and are a safety mechanism since it guards access to resources, and it's dangerous if it falls into the wrong hands!&lt;/p&gt;

&lt;h3&gt;
  
  
  Refresh token &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The Refresh token allows us to exchange it for new, shiny tokens. This optional &lt;code&gt;offline_access&lt;/code&gt; scope we added in the original authorization code request allows the access token to be short-lived but does not require Sunny to authenticate to get a new token repeatedly. Refresh tokens can be longer-lived than access tokens, but for public clients, the lifetime of Refresh tokens should also be short. We want to make sure bad actors can't get a hold of a Refresh token to gain access to an access token! For public clients like SPA, it's a best practice also to use &lt;strong&gt;Refresh Token rotation&lt;/strong&gt;, which improves security by rotating refresh tokens after each use.&lt;/p&gt;

&lt;p&gt;While each step of this OAuth flow to get the tokens is critical to ensure a secure authentication and authorization process, let's inspect the two requests in more detail. &lt;/p&gt;

&lt;h2&gt;
  
  
  Create an OAuth 2.0 + OIDC Compliant Authorization server &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We'll start by setting up an authorization server in Okta and use the &lt;a href="https://oidcdebugger.com/" rel="noopener noreferrer"&gt;OpenID Connect Debugger&lt;/a&gt; tool to inspect the Network requests. This authorization server is OAuth 2.0 and OIDC compliant so we can use it within applications that conform to those specs.&lt;/p&gt;

&lt;p&gt;Before you begin, you’ll need a free Okta developer account. Install the &lt;a href="https://cli.okta.com/" rel="noopener noreferrer"&gt;Okta CLI&lt;/a&gt; and run &lt;code&gt;okta register&lt;/code&gt; to sign up for a new account. If you already have an account, run &lt;code&gt;okta login&lt;/code&gt;. Then, run &lt;code&gt;okta apps create&lt;/code&gt;. Select the default app name, or change it as you see fit. Choose &lt;strong&gt;Single-Page App&lt;/strong&gt; and press &lt;strong&gt;Enter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;https://oidcdebugger.com/debug&lt;/code&gt; for the Redirect URI and set the Logout Redirect URI to &lt;code&gt;https://oidcdebugger.com/debug&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;
  What does the Okta CLI do?
  &lt;br&gt;
The Okta CLI will create an OIDC Single-Page App in your Okta Org. It will add the redirect URIs you specified and grant access to the Everyone group. It will also add a trusted origin for &lt;code&gt;https://oidcdebugger.com/debug&lt;/code&gt;. You will see output like the following when it’s finished:&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Okta application configuration:
Issuer:    https://dev-133337.okta.com/oauth2/default
Client ID: 0oab8eb55Kb9jdMIr5d6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: You can also use the Okta Admin Console to create your app. See &lt;a href="https://developer.okta.com/docs/guides/sign-into-spa/-/create-okta-application/" rel="noopener noreferrer"&gt;Create a Single-Page App&lt;/a&gt; for more information.&lt;br&gt;
&lt;/p&gt;

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

&lt;p&gt;Make a note of the &lt;code&gt;Issuer&lt;/code&gt; and &lt;code&gt;Client ID&lt;/code&gt;. In the upcoming steps, you'll need those values to configure Okta in your SPA client.&lt;/p&gt;

&lt;h2&gt;
  
  
  View the well-known endpoint for OIDC Discovery &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Authorization servers have standard, public endpoints for discovery by clients. Let's take a peek at the OIDC discovery document.&lt;/p&gt;

&lt;p&gt;The OpenID Connect specification requires a standardized mechanism for client discovery. You can find it at &lt;code&gt;{Issuer}/.well-known/openid-configuration&lt;/code&gt;. Open up a browser tab to the OIDC discovery endpoint. It is also JSON formatted data that looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fhi2ndc3rbnpyk9dlyi5b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fhi2ndc3rbnpyk9dlyi5b.jpg" alt="Example OIDC well-known discovery document" width="800" height="776"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the discovery response, we have the endpoints for the authorization and token requests which we'll use in the following steps. We also have a user info endpoint to query for user information and endpoints to validate the ID token. If you find the property for &lt;code&gt;claims_supported&lt;/code&gt;, you'll see the claims cover various identifying information about the user. &lt;/p&gt;

&lt;h2&gt;
  
  
  Debug the authorization code and token requests &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We can see this OAuth flow using the &lt;a href="https://oidcdebugger.com/" rel="noopener noreferrer"&gt;OpenID Connect Debugger&lt;/a&gt; tool. Open the site on a browser with good developer debugging capabilities. You'll see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ff6mhcqa452s6f8c2mcye.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ff6mhcqa452s6f8c2mcye.jpg" alt="OIDC debugger site showing form fields" width="800" height="686"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some fields are pre-populated, which is helpful. Add the other key information needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authorize URI (required)&lt;/strong&gt; - the authorize endpoint from the discovery doc&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client ID (required)&lt;/strong&gt; - the Client ID value from Okta CLI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope (required)&lt;/strong&gt; - &lt;code&gt;openid&lt;/code&gt; is already added for us. Add &lt;code&gt;profile&lt;/code&gt; and &lt;code&gt;offline_access&lt;/code&gt; with spaces in between. The form field should look like &lt;code&gt;openid profile offline_access&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response type (required)&lt;/strong&gt; - select "Use PKCE?" to unlock a few new fields, but everything is auto-populated. The debugger discovers the token endpoint automatically for us. 😎&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open debugging tools in your browser to watch for redirection and network requests. You'll want to make sure you're preserving logs between page refreshes. &lt;/p&gt;

&lt;p&gt;At the bottom of the page, you'll see how the authorization code request is formed. Press &lt;strong&gt;Send Request&lt;/strong&gt; to start the flow.&lt;/p&gt;

&lt;p&gt;First, you'll authenticate using Okta if you still need to sign in by redirecting to an Okta-hosted sign-in page. Redirecting to the Identity Provider's hosted sign-in page is the best practice for security, so it's also a common practice you'll see across Identity Providers. Completing sign-in redirects you back to the OIDC debugger with a success message. You'll see the authorization code automatically exchanged for tokens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fqyo0zws9enum226uafsx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fqyo0zws9enum226uafsx.jpg" alt="Authorization code and tokens returned in the OIDC debugger upon successful sign-in" width="800" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The token format for ID tokens is JSON Web Token (JWT). The access token from Okta is also a JWT. JWT is an open standard (RFC 7519) that allows systems to exchange information in JSON format securely. They are compact and safe from modifications, but our tokens contain public information. Don't worry! They are secure, just not confidential. &lt;/p&gt;

&lt;p&gt;You can copy the access token or ID token value from the response and read the contents using a &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JWT debugger&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F92puzmi811rvcxfplkgx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F92puzmi811rvcxfplkgx.jpg" alt="JWT inspection in the JWT debugger" width="800" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So this is cool, but what do we do with the tokens in our SPA? Let's bring these concepts into our front-end application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add authentication to your SPA &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;First, we need an Okta OIDC application supporting our SPA's redirect URI. We could edit the existing OIDC debugger application we created previously, or we can use a handy Okta CLI command to set everything up for us and to scaffold out a sample application in our preferred framework.&lt;/p&gt;

&lt;p&gt;Use the following command in the terminal to get going quickly. There's a separate command for each Angular, React, and Vue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Angular&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;okta start angular
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;React&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;okta start react
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Vue&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;okta start vue
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Follow the instructions in the terminal to start the application. You should be able to sign in and sign out. Additionally, you can watch network requests for the calls it makes.&lt;/p&gt;

&lt;p&gt;We don't have a refresh token by default. You can enable that in the Okta Admin Console. Navigate to the &lt;a href="https://developer.okta.com/" rel="noopener noreferrer"&gt;Okta Developer site&lt;/a&gt; and sign in to your Okta organization. In the Admin Console, navigate to &lt;strong&gt;Applications&lt;/strong&gt; &amp;gt; &lt;strong&gt;Applications&lt;/strong&gt; and select the Okta application for the SPA you created. Edit the settings to enable &lt;strong&gt;Refresh Token&lt;/strong&gt;. It automatically adds Refresh Token Rotation. Save your changes.&lt;/p&gt;

&lt;p&gt;If you still need to, open the SPA code in your favorite IDE. Depending on your framework, navigate to the &lt;code&gt;config.js&lt;/code&gt; or &lt;code&gt;app.config.ts&lt;/code&gt; file. You'll see the OIDC config and property for &lt;code&gt;scopes&lt;/code&gt; where you will add &lt;code&gt;offline_access&lt;/code&gt;. Your OIDC config looks something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;clientId:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;issuer:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ISSUER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;redirectUri:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;window.location.origin&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="err"&gt;'/login/callback'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;scopes:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'openid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'profile'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'offline_access'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now try rerunning the SPA. If you inspect the network request, you'll see the refresh token too. You can see the tokens by looking at the contents of your local storage too.&lt;/p&gt;
&lt;h2&gt;
  
  
  Use auth tokens in SPAs &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we have these tokens in our SPA, what do we do with them? Let a trusted OIDC library, such as the Okta SDKs, handle all the token requests and refresh them for us. Behind the scenes, the OIDC library is hard at work exchanging tokens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F7bem3wfvxmcytf40i7jx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F7bem3wfvxmcytf40i7jx.jpg" alt="Refresh token call to the authorization server and returning new tokens" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're primarily interested in the contents of the ID token and using the access token.&lt;/p&gt;
&lt;h3&gt;
  
  
  How to use the access token &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The access token gives us access to resources. That means we use access tokens in outgoing API requests that our application needs, like for Sunny to get their next rawring lesson.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fjyolh1fzvpuvfttehaiy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fjyolh1fzvpuvfttehaiy.jpg" alt="Sunny starting up a new lesson makes a call to the Rawr site's /lesson endpoint passing in the access token" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll send the access token as a Bearer token in the HTTP call's Authorization header. So in the case of Sunny, the outgoing HTTP call looks like this.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /lessons
Authorization: Bearer access_token_value
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You'll want to ensure you're not adding the access token to calls outside your system by maintaining an allowlist of origins that should include the token.&lt;/p&gt;

&lt;p&gt;A great way to manage adding the Authorization header and the logic to verify the call matches the allowlist of origins is using an interceptor. Interceptors sit between your application and outgoing (or incoming) HTTP requests. Angular includes the concept of interceptors within the framework, and if you use Axios in Vue or React apps, you can configure interceptors there.&lt;/p&gt;

&lt;p&gt;You can see access tokens in action within the SPA you previously created. If you navigate to &lt;strong&gt;Messages&lt;/strong&gt; in the application, it will make a call to a resource server and add the access token to the Authorization header. If you want to see the messages request succeed, you'll need to run the resource server in Okta's &lt;a href="https://github.com/okta/samples-nodejs-express-4" rel="noopener noreferrer"&gt;samples-nodejs-express-4 repo&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/okta" rel="noopener noreferrer"&gt;
        okta
      &lt;/a&gt; / &lt;a href="https://github.com/okta/samples-nodejs-express-4" rel="noopener noreferrer"&gt;
        samples-nodejs-express-4
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Express 4 samples. Will publish an artifact that can be consumed by end-to-end sample repos
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Express Sample Applications for Okta&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This repository contains several sample applications that show you how to integrate various Okta use-cases into your Node.js application that uses the Express framework.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Configuration&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;All of the samples share a single configuration file, &lt;a href="https://github.com/okta/samples-nodejs-express-4config.js" rel="noopener noreferrer"&gt;config.js&lt;/a&gt;. The config uses environment variables which can be either exported in the shell or stored in a file named &lt;code&gt;testenv&lt;/code&gt; in this directory. See &lt;a href="https://www.npmjs.com/package/dotenv" rel="nofollow noopener noreferrer"&gt;dotenv&lt;/a&gt; for more details on this file format. It may look something like:&lt;/p&gt;

&lt;div class="highlight highlight-source-ini notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;ISSUER&lt;/span&gt;=https://yourOktaDomain.com/oauth2/default

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Web app&lt;/span&gt;
&lt;span class="pl-k"&gt;CLIENT_ID&lt;/span&gt;=123XX
&lt;span class="pl-k"&gt;CLIENT_SECRET&lt;/span&gt;=456XX

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; SPA app&lt;/span&gt;
&lt;span class="pl-k"&gt;SPA_CLIENT_ID&lt;/span&gt;=123YY
&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Please find the sample that fits your use-case from the table below.&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sample&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Use-Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/okta/samples-nodejs-express-4/okta-hosted-login" rel="noopener noreferrer"&gt;Okta-Hosted Login&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;An application server that uses the hosted login page on your Okta org, then creates a cookie session for the user in the Express application.&lt;/td&gt;
&lt;td&gt;Traditional web applications with server-side rendered pages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/okta/samples-nodejs-express-4/custom-login" rel="noopener noreferrer"&gt;Custom Login Page&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;An application server that uses the&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/okta/samples-nodejs-express-4" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;h3&gt;
  
  
  How to use the ID token &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Since the ID token contains user identity information, you can use it to start populating your user store and for supporting identifiers you need immediately, such as their name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F1wcn7wcbs6qjuau1d8xs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F1wcn7wcbs6qjuau1d8xs.jpg" alt="Sunny looking at his profile in the Rawr app where they see their name, dinosaur family, and their avatar" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the SPA you previously created, you can see all your claims if you navigate to &lt;strong&gt;Profile&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The Okta SDK automatically decodes the ID token so that we can use the claims without decoding the payload ourselves. But before we jump right into using the claims, the Okta SDK first validates the token signature, which helps ensure the token's integrity and that it hasn't been altered. Let's take a quick peek under the covers at what happens during this validation process.&lt;/p&gt;

&lt;p&gt;Since this token is a JWT, we can rely on standard validation for JWTs for the validity of the token itself. Next, it will validate some claims in the payload, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;iss&lt;/code&gt; - the issuer, which should match the original request. In the OIDC Debugger tool, we passed this in as the "Authorize URI"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aud&lt;/code&gt; - the audience, which should match the client ID of your Okta application&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nonce&lt;/code&gt; - an arbitrary one-time value that should match the original request. In the OIDC Debugger tool, it was pre-populated for us.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exp&lt;/code&gt; and &lt;code&gt;iat&lt;/code&gt; - the expiry time and issued at times, respectively. Only non-expired tokens with an expected issue time here, please!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have the access token, you can also make a request to the OIDC Discovery document's User Info endpoint, which may contain more information about the user than what is available in your ID token. You may also need to add any user information and user settings from API calls within your system into your user store since the SPAs we write have complex user information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more about OAuth, OIDC, tokens, and authentication best practices &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Hopefully, this gives insight into how authentication and authorization with OAuth 2.0 + OpenID Connect work for public clients like SPAs and how each token fits into the landscape.&lt;/p&gt;

&lt;p&gt;If you liked this post, you might want to check out the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/06/01/oauth-public-client-identity" rel="noopener noreferrer"&gt;The Identity of OAuth Public Clients&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2019/05/01/is-the-oauth-implicit-flow-dead" rel="noopener noreferrer"&gt;Is the OAuth 2.0 Implicit Flow Dead?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2021/10/29/things-to-keep-in-mind-about-auth" rel="noopener noreferrer"&gt;The Things to Keep in Mind about Auth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2023/04/04/blog/2022/10/14/quick-javascript-authentication" rel="noopener noreferrer"&gt;Quick JavaScript Authentication with OktaDev Schematics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember to follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and subscribe to our &lt;a href="https://www.youtube.com/c/OktaDev/" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for more exciting content. We also want to hear about what tutorials you want to see. Leave us a comment below.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>A Practical Guide to Providers in Angular</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Wed, 09 Nov 2022 15:51:35 +0000</pubDate>
      <link>https://forem.com/angular/a-practical-guide-to-providers-in-angular-3c96</link>
      <guid>https://forem.com/angular/a-practical-guide-to-providers-in-angular-3c96</guid>
      <description>&lt;p&gt;When creating apps with Angular, you can add and configure dependencies for the application you’re building using something called "providers.” You use the built-in &lt;strong&gt;D&lt;/strong&gt;ependency &lt;strong&gt;I&lt;/strong&gt;njection (&lt;strong&gt;DI&lt;/strong&gt;) system to create providers. This post will cover Angular’s powerful DI system at a high level and demonstrate a few practical use cases and strategies for configuring your dependencies. Let’s get practical!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick overview of Dependency Injection&lt;/li&gt;
&lt;li&gt;Angular's Dependency Injection system&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Injector&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Providing to different injectors&lt;/li&gt;
&lt;li&gt;Injection tokens in Angular&lt;/li&gt;
&lt;li&gt;
Configuring providers in Angular's Dependency Injection system

&lt;ul&gt;
&lt;li&gt;Configure providers with &lt;code&gt;useClass&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Configure providers with &lt;code&gt;useExisting&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Configure with &lt;code&gt;useValue&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Configure with &lt;code&gt;useFactory&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Learn more about Angular Dependency Injection&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick overview of Dependency Injection &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Dependency Injection decouples the creation of a dependency from using that dependency. When you use DI, it promotes loose coupling within our code - a foundation for creating well-architected software. Practicing good software design patterns yields flexible, maintainable software that allows our applications to grow with new features more quickly. And by using DI, we can change the dependent code without changing the consuming code! Seamless code switches are nearly impossible with tightly coupled code, where you might have to touch everything to make a small change.&lt;/p&gt;

&lt;p&gt;The cool thing is Angular has DI built-in and helps set us up for success. How handy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular’s Dependency Injection system &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When you use the Angular CLI to generate a service, it automatically adds the code to register the service within Angular’s DI system for us. 🎉 Services contain business logic code that we want to keep separate from view logic.&lt;/p&gt;

&lt;p&gt;When Angular CLI generates a service, it adds an &lt;code&gt;@Injectable()&lt;/code&gt; TypeScript decorator, which is the bit of code that registers a service within the Angular DI system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;class&lt;/span&gt; &lt;span class="nc"&gt;MyService&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;Without doing anything else, we can use our dependency in the application by injecting it into the consuming code as a constructor parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// standard component metadata here&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;MyComponent&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;myService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyService&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;blockquote&gt;
&lt;p&gt;In Angular v14, you have a new option to use the &lt;code&gt;inject()&lt;/code&gt; function instead of injecting the service into the consumer as a constructor parameter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Angular CLI is 💯! The generated service allows you to start using your service immediately, and the &lt;code&gt;Injectable()&lt;/code&gt; TypeScript decorator is tree-shakeable so it's an all-around win!&lt;/p&gt;

&lt;p&gt;Another way to register dependencies is to provide them manually through the &lt;code&gt;providers&lt;/code&gt; array. Different Angular building blocks accept providers in the metadata. So you can register a &lt;code&gt;provider&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// stuff here&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// stuff here&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;MyService&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s something else to note, though. Angular’s DI system allows you to provide a dependency to different places within the application. We saw this example in the first code snippet of the &lt;code&gt;@Injectable()&lt;/code&gt; TypeScript decorator. Angular CLI automatically generates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;class&lt;/span&gt; &lt;span class="nc"&gt;MyService&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 configuration option &lt;code&gt;providedIn: 'root'&lt;/code&gt; specifies where within the application to provide the service. In this case, we’re saying provide to “root,” which means the application's root. When you provide at the root of the application, it a single instance of the service is available across the entirety of the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;Injector&lt;/code&gt; &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Injector&lt;/code&gt; is the mechanism for handling DI. It manages the dependencies and gives you the dependency you request. Angular has multiple injectors, and the injectors are hierarchical. 💫 There are different categories of injectors - Module Injectors, Element Injectors, and a special fallback injector called the Null Injector. Whenever I think of a hierarchy, I can't help but think about a tree. 🌳 So we can visualize the injector hierarchy like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fomrkgu8m0tlmfnmx13cf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fomrkgu8m0tlmfnmx13cf.jpg" alt="Injector hierarchy on an upside down cartoon tree graphic" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Going back to the example we had above when we use the instruction &lt;code&gt;providedIn: 'root'&lt;/code&gt;, what we're doing is providing to a particular module injector, the &lt;strong&gt;Root Injector&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Providing to different injectors &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You can configure the &lt;code&gt;providers&lt;/code&gt; array in other modules and Angular building blocks, such as components and directives. This means you can create an instance of a dependency available to your module and everything in it or only to your component. You might consider these options if you need a 1:1 relationship between an instance of the dependency and the consumer, such as if you maintain state specifically for a module or component within your dependency. Be careful to avoid causing unnecessary complexity, though!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In Angular v14, you can provide to routes as part of your route paths definitions! Angular v15 deprecates a confusing option for the &lt;code&gt;providedIn&lt;/code&gt; configuration called &lt;code&gt;any&lt;/code&gt; used explicitly for lazy-loaded modules, as well as assigning specific modules in the configuration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because you can provide to so many different places, Angular has to resolve which instance of a dependency you get when you consume it. You’ll get the provider you configured closest to the consuming code as a general rule, and move up the tree to find the requested dependency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fal0hacfs75408i0dy629.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fal0hacfs75408i0dy629.jpg" alt="Same image of tree with injectors with an arrow pointing up the tree to show the resolution path" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Still, this resolution process is complex, and it can be difficult to figure out what's going on when using a dependency with such a complicated setup. Fortunately, the Angular team announced plans for better debugging tools that help us understand where a dependency comes from. 🎉&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CABHcf1gCbg?start=2928"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As with most things, the most straightforward, simplest approach is best. If you can get away with providing to the Root Injector so that you only have one instance of dependency for your application, then you should.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fu7rhblvnauvi08xc6izl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fu7rhblvnauvi08xc6izl.jpg" alt="Decision chart showing to use 'root' if a dependency can be a single instance within the application, otherwise use module or element injectors" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While having this level of configurability sounds unnecessarily complicated, it allows you to fine-tune which dependency to use in your consuming code. Now that we have a quick overview of how and where to provide dependencies let’s review an integral piece of Angular’s DI system, injection tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Injection tokens in Angular &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Injection tokens allow us to have values and objects as dependencies. This means we can depend on strings, such as “Hello world!” and objects, which include configuration objects and global variables, such as Web APIs. But injection tokens are even more remarkable because we can also create dependencies to constructs that don’t have a runtime definition, such as interfaces! Let’s take a look at an example using an injection token.&lt;/p&gt;

&lt;p&gt;Let's say you work on a language learning application with a user configuration that includes the language the user is learning. You have an interface definition of the configuration as well as a concrete instance of the configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="nx"&gt;defaultUserConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&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;You can register the token to Angular's DI system and return the default configuration by providing the type, a description, and options like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;USER_CONFIG_TOKEN&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;InjectionToken&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;userconfig&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="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;factory&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="nx"&gt;defaultUserConfig&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you want to use the &lt;code&gt;USER_CONFIG_TOKEN&lt;/code&gt;, you will use the &lt;code&gt;@Inject&lt;/code&gt; decorator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// standard component metadata here&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;MyUserProfileComponent&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;USER_CONFIG_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&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;UserConfig&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;Now we can access the user config from within the component! Accessing a config might not seem like a big deal, but we used injection tokens to inject an &lt;strong&gt;interface&lt;/strong&gt; into the component! Having injection tokens as a means to represent values and interfaces as dependencies are enormous! And it sets us up to leverage the power of Angular’s DI system.&lt;/p&gt;

&lt;p&gt;We can use injection tokens and configure providers within Angular’s DI system for more power and fine-grained control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring providers in Angular’s Dependency Injection system &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You can configure the &lt;code&gt;providers&lt;/code&gt; array to add fine-grained control to your providers. When combined with injection tokens, we can unleash a lot of power. But first, it’s essential to know when it makes sense to do so. Always prefer the most straightforward, default way of registering a dependency and then use fine-grained control as needed.&lt;/p&gt;

&lt;p&gt;To configure the &lt;code&gt;providers&lt;/code&gt; array, you add an object containing the instructions like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// stuff here&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// stuff here&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="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;howToProvide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OtherDependency&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The “how to provide” gives Angular-specific instructions on this dependency configuration. Then you can provide the other new dependency. Angular supports the following options for “how to provide”:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useClass&lt;/code&gt; - Replace the current dependency with a new instance of something else&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useExisting&lt;/code&gt; - Replace the current dependency with an existing dependency&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useValue&lt;/code&gt; - Replace the current dependency with a new value&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useFactory&lt;/code&gt; - Use a factory method to determine which dependency to use based on a dynamic value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, let’s walk through examples of each configuration option to understand how to use them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure providers with &lt;code&gt;useClass&lt;/code&gt; &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;useClass&lt;/code&gt; option replaces the current dependency with a new instance of another class. This is a great option if you’re refactoring code and want to substitute a different dependency in your application quickly. Let’s say you have a language learning app and an Angular service that wraps the authentication calls you delegate to an auth library and an auth provider. We’ll call this service &lt;code&gt;AuthService&lt;/code&gt;, and keep the code straightforward like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;class&lt;/span&gt; &lt;span class="nc"&gt;AuthService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;In a stroke of luck, a large tech company decides to buy your language learning app, requiring you to authenticate using their social login only. You can create a new authentication service that wraps the calls to their auth provider and keeps the same member names; we’ll call it &lt;code&gt;NewAuthService&lt;/code&gt;. (Note, you should not name your services with these terrible generic names. Be a bit more descriptive. )&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;class&lt;/span&gt; &lt;span class="nc"&gt;NewAuthService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* new way to login */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* new way to 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;Because both classes have the same public members, you can substitute the original &lt;code&gt;AuthService&lt;/code&gt; with the new &lt;code&gt;NewAuthService&lt;/code&gt; by configuring the provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// imports here&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;//declarations here&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;AuthService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NewAuthService&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;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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cool thing about having the same public members is that there’s no need to change the consuming code. Angular instantiates a new instance of &lt;code&gt;NewAuthService&lt;/code&gt; and provides that dependency to consuming code, even if they still refer to &lt;code&gt;AuthService&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;It might not make sense to keep the original &lt;code&gt;AuthService&lt;/code&gt; around, so you might want to consider transferring all the code references to use the &lt;code&gt;NewAuthService&lt;/code&gt; only. However, the &lt;code&gt;useClass&lt;/code&gt; configuration option is a fast way for us to quickly substitute one instance of a class for another, which means proofs-of-concept and quick checks can be super-fast!&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure providers with &lt;code&gt;useExisting&lt;/code&gt; &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;useExisting&lt;/code&gt; option replaces the provider with a different provider already existing within the application. This option is a great use case for API narrowing, that is, decreasing the surface area of an API. Let’s say your language learning application has an unwieldy API. We’ll call this API &lt;code&gt;LanguageTranslationService&lt;/code&gt;, and it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;LanguageTranslationService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;french&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* translates to French */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;japanese&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* translates to Japanese */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;elvish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* translates to Elvish */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;klingon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* translates to Klingon */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// so on and so forth, but you see the problem here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you consume the service like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// standard component metadata here&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;ElvishTranslationComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;elvish&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;translationService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LanguageTranslationService&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;public&lt;/span&gt; &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;elvish&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;translationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elvish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someText&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;Oops… The &lt;code&gt;LanguageTranslationService&lt;/code&gt; looks a bit unwieldy. Let’s narrow the API surface by creating a new class called &lt;code&gt;FictitiousLanguageTranslationService&lt;/code&gt; and move the translation methods for the fictitious languages there. We’ll use an abstract class for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FictitiousLanguageTranslationService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nx"&gt;elvish&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nx"&gt;klingon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&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;Now we can add &lt;code&gt;FictitiousLanguageTranslationService&lt;/code&gt; as a real dependency in the application by adding it to the &lt;code&gt;providers&lt;/code&gt; array, but use the existing &lt;code&gt;LanguageTranslationService&lt;/code&gt; implementation of the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// imports here&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// declarations here&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="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FictitiousLanguageTranslationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;useExisting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LanguageTranslationService&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we’ll update the consumer to use the new dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// standard component metadata here&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;ElvishTranslationComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;elvish&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;fltService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FictitiousLanguageTranslationService&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;public&lt;/span&gt; &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;elvish&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;translationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elvish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someText&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;Only the methods defined in the &lt;code&gt;FictitiousLanguageTranslationService&lt;/code&gt; are available now. Pretty sweet!&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure with &lt;code&gt;useValue&lt;/code&gt; &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;useValue&lt;/code&gt; option replaces the provider with a value. This option is a great use case for configurations and mocking services in automated tests where you need to control the inputs and outputs. Let’s go back to the &lt;code&gt;USER_CONFIG_TOKEN&lt;/code&gt; in this example and override it to show a different language instead.&lt;/p&gt;

&lt;p&gt;We can override the token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&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="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;USER_CONFIG_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jp&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyUserProfileComponent&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;USER_CONFIG_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;userConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserConfig&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;Now when we use this in the &lt;code&gt;MyUserProfileComponent&lt;/code&gt; we’ll see the user's language is Japanese instead of English!&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure with &lt;code&gt;useFactory&lt;/code&gt; &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;useFactory&lt;/code&gt; option allows us to use a factory method to create a dependency. This option is a great use case if you have dynamic values to consider when creating the dependency. It’s also how we can use a factory pattern for creating our dependencies.&lt;/p&gt;

&lt;p&gt;In this example, let’s say in your Language Learning application, if the user is learning Japanese, we want to show the Japanese flag in the &lt;code&gt;MyUserProfileComponent&lt;/code&gt; instead of the default - a checkered flag. The user’s language selection is in the user’s config, so the example code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// imports here&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// declarations here&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="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;USER_CONFIG_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="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserConfig&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;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jp&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="s1"&gt;🇯🇵&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="s1"&gt;🏁&lt;/span&gt;&lt;span class="dl"&gt;'&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;UserConfig&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;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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice we were able to pass in a dependency to the configuration option. The &lt;code&gt;useClass&lt;/code&gt; and &lt;code&gt;useFactory&lt;/code&gt; options support passing in dependencies.&lt;/p&gt;

&lt;p&gt;Now when we use the configuration in the &lt;code&gt;MyUserProfileComponent&lt;/code&gt; we’ll get the Japanese flag instead of a checkered flag only if the user’s configuration has Japanese as their language!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// standard component metadata here&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;MyUserProfileComponent&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;USER_CONFIG_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&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;UserConfig&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;// flag is either 🏁 or 🇯🇵 based on the language setting&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;
  
  
  Learn more about Angular Dependency Injection &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This article offers a high-level overview of Angular’s DI system. As you can already see, it’s a powerful system with many different configuration options and complexity. As a result, even though Angular has these configuration options, using the most straightforward approach will make troubleshooting and maintenance easier! 🏆&lt;/p&gt;

&lt;p&gt;Angular's documentation has great resources! There are many docs on Dependency Injection since it's such a broad topic. Here's where to get started - &lt;a href="https://angular.io/guide/dependency-injection-overview" rel="noopener noreferrer"&gt;Dependency injection in Angular&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This post was originally published on the &lt;a href="https://developer.okta.com/blog/2022/10/11/angular-dependency-injection" rel="noopener noreferrer"&gt;Okta Developer blog&lt;/a&gt;. I am the original author and made modifications.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Protect Your Angular App From Cross-Site Scripting</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Wed, 27 Jul 2022 14:55:51 +0000</pubDate>
      <link>https://forem.com/oktadev/protect-your-angular-app-from-cross-site-scripting-26d4</link>
      <guid>https://forem.com/oktadev/protect-your-angular-app-from-cross-site-scripting-26d4</guid>
      <description>&lt;p&gt;In the last post of this SPA security series, we covered Cross-Site Request Forgery (CSRF) and how Angular helps you with a mitigation technique. &lt;/p&gt;

&lt;p&gt;Next, we'll dive into Cross-Site Scripting (XSS) and look at the built-in security guards you get when using Angular.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-Site Scripting (XSS) protection
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://developer.okta.com/blog/2022/07/08/spa-web-security-csrf-xss" rel="noopener noreferrer"&gt;second post of this series&lt;/a&gt;, we presented an overview of Cross-Site Scripting (XSS). In summary, you learned that XSS occurs when code pollutes data and your application doesn't provide safeguards to prevent the code from running.&lt;/p&gt;

&lt;p&gt;Let's recap the example attack vector.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Imagine an overly dramatic but otherwise innocent scenario like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A website allows you to add comments about your favorite K-Drama.&lt;/li&gt;
&lt;li&gt;An agitator adds the comment &lt;code&gt;&amp;lt;script&amp;gt;alert('Crash Landing on You stinks!');&amp;lt;/script&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;That terrible comment saves as is to the database.&lt;/li&gt;
&lt;li&gt;A K-Drama fan opens the website.&lt;/li&gt;
&lt;li&gt;The terrible comment is added to the website, appending the &lt;code&gt;&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; tag to the DOM.&lt;/li&gt;
&lt;li&gt;The K-Drama fan is outraged by the JavaScript alert saying their favorite K-Drama, &lt;a href="https://www.imdb.com/title/tt10850932/" rel="noopener noreferrer"&gt;Crash Landing on You&lt;/a&gt;, stinks.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this example, we have a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element and glossed over the steps for appending the element to the DOM. In reality, polluted data gets pulled into the application in various ways. Adding untrusted data in an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API#injection_sinks" rel="noopener noreferrer"&gt;injection sink&lt;/a&gt; - a Web API function that allows us to add dynamic content to our applications - is a major culprit. Examples of sinks include, but aren't limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;methods to append to the DOM such as  &lt;code&gt;innerHTML&lt;/code&gt;, &lt;code&gt;outerHTML&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;approaches that load external resources or navigate to external sites via a URL, such as &lt;code&gt;src&lt;/code&gt; or &lt;code&gt;href&lt;/code&gt; for HTML elements and &lt;code&gt;url&lt;/code&gt; property on styles&lt;/li&gt;
&lt;li&gt;event handlers, such as &lt;code&gt;onmouseover&lt;/code&gt; and &lt;code&gt;onerror&lt;/code&gt; with an invalid &lt;code&gt;src&lt;/code&gt; value&lt;/li&gt;
&lt;li&gt;global functions that evaluate and/or run code, such as &lt;code&gt;eval()&lt;/code&gt;, &lt;code&gt;setTimeout()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, there are many vectors for the vulnerability. Many of these sinks have legitimate use cases when building dynamic web applications. Since the sinks are necessary for web app functionality, we must use trusted data by escaping and sanitizing it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is still a high-level summary. The fine print is that XSS vulnerabilities can be pretty sneaky in the different ways the attack can occur.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are different XSS attacks, each with a slightly different attack vector. We'll briefly cover how three attacks work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stored XSS
&lt;/h3&gt;

&lt;p&gt;In this flavor of XSS, the attack is persisted somewhere, like in a database. We recapped &lt;em&gt;stored XSS&lt;/em&gt; in the example above, where an agitator's terrible comment with the &lt;code&gt;script&lt;/code&gt; tag persists in the database and ruins someone else's day by showing the unfriendly comment in an alert.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reflected XSS
&lt;/h3&gt;

&lt;p&gt;In this attack, the malicious code sneaks in through the HTTP request, usually through URL parameters. Suppose the K-Drama site takes a search term via a URL parameter, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://myfavekdramas.com/dramas?search=crash+landing+on+you
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The site then takes the search terms and displays them back to the user while calling out to the backend to run the search.&lt;/p&gt;

&lt;p&gt;But what if an agitator constructs a URL like this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://myfavekdramas.com/dramas?search=&amp;lt;img src=1 onerror="alert('Doh!')"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may think that you'd never navigate to a link like that! Who would?! But let's remember, in a previous post, you &lt;em&gt;did&lt;/em&gt; click the link in your spam email to send money to your high school sweetheart. This isn't meant as a judgment; no one is immune to clicking fishy links. Also, agitators are pretty tricksy. They might use URL shorteners to obscure the risk. &lt;/p&gt;

&lt;h3&gt;
  
  
  DOM-based XSS
&lt;/h3&gt;

&lt;p&gt;In this attack, the agitator takes advantage of Web APIs. The attack occurs entirely within the SPA, and it's pretty much identical to &lt;em&gt;reflected XSS&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Let's say our application depends on an external resource—the app embeds an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; for showing trailers for the K-Dramas and sets the &lt;code&gt;iframe&lt;/code&gt;'s &lt;code&gt;src&lt;/code&gt; attribute to an external site. So our code might look like this.&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;iframe&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{resourceURL}"&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;We usually call out to the third-party service to get the URLs for the source, but agitators have infiltrated this third-party service and now control the resource URLs returned, making our code look like this.&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;iframe&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"javascript:alert('Boo!')"&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;Well, darn it, we've got some problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  XSS support in Angular
&lt;/h2&gt;

&lt;p&gt;Fortunately, Angular has a lot of built-in security protections. It treats all values as suspicious and untrusted by default, which is incredibly helpful because the framework automatically guards us against unintentionally creating vulnerabilities in our applications. Angular automatically removes any &lt;code&gt;script&lt;/code&gt; tags so we won't have to worry about the original hypothetical example.&lt;/p&gt;

&lt;p&gt;Let's see some examples of how Angular protects us against XSS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular automatically escapes values
&lt;/h3&gt;

&lt;p&gt;Web applications implement comment features like in the Stored XSS example by calling an API to get a list of comments, then add the comments to the template. In Angular, an extremely simplified comments component might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-comments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;p *ngFor="let comment of comments | async"&amp;gt;
      {{comment}}
    &amp;lt;p&amp;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;CommentsComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;comments&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="kr"&gt;string&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;commentsService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CommentsService&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;public&lt;/span&gt; &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;comments&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;commentsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getComments&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 XSS attack vector works only if the web app treats all values as trustworthy and appends them directly to the template, such as when the web app doesn't escape or sanitize values first. Luckily, Angular automatically does both.&lt;/p&gt;

&lt;p&gt;When you add values through interpolation in templates (using the &lt;code&gt;{{}}&lt;/code&gt; syntax), Angular automatically escapes the data. So the comment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="javascript:alert(\'Crash Landing on You stinks!\')"&amp;gt;Click to win a free prize!&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;displays exactly like what's written above as text. It's still a terrible comment and unfriendly to "Crash Landing on You" fans, but it doesn't add the anchor element to the app. This is awesome because even if the attack were more malicious, it still wouldn't perform any actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular automatically sanitizes values
&lt;/h3&gt;

&lt;p&gt;Let's say we want to display the comments preserving any safe markup a user enters. We already have two malicious comments to start us off on shaky ground:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;a href="javascript:alert(\'Crash Landing on You stinks!\')"&amp;gt;Click to win a free prize!&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;img src=1 onerror="alert('Doh!')"/&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then a K-Drama fan adds a new comment with safe markup.&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;strong&amp;gt;&lt;/span&gt;It's a wonderful drama! The best!&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the &lt;code&gt;CommentsComponent&lt;/code&gt; uses interpolation to populate the comments, the comments will display in the browser in text like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F8n64zokb5i954wxcpake.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F8n64zokb5i954wxcpake.jpg" alt="Screenshot of comments as shown in the browser. Is it the text of each comment include code blocks as text." width="800" height="153"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's not what we want! We want to interpret the HTML and allow the &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt; text, so we change our component template to bind it to the HTML &lt;code&gt;innerHTML&lt;/code&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; 
  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;ngFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;let comment of comments | async&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comment&lt;/span&gt;&lt;span class="dl"&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;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the site displays only the second comment correctly formatted like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fitaaton9bs25kz5idjs9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fitaaton9bs25kz5idjs9.jpg" alt="Screenshot of comments in the browser when bound to the innerHTML property. It shows a broken image and the new comment in strong font-weight." width="700" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first comment with the &lt;code&gt;anchor&lt;/code&gt; tag doesn't display the alert when clicked! The second comment with the attack in the &lt;code&gt;onerror&lt;/code&gt; handler only shows the broken image and doesn't run the error code! Angular doesn't publish a list of unsafe tags. Still, we can sneak a peek into the codebase to see Angular considers tags such as &lt;code&gt;form&lt;/code&gt;, &lt;code&gt;textarea&lt;/code&gt;, &lt;code&gt;button&lt;/code&gt;, &lt;code&gt;embed&lt;/code&gt;, &lt;code&gt;link&lt;/code&gt;, &lt;code&gt;style&lt;/code&gt;, &lt;code&gt;template&lt;/code&gt; as suspicious and may altogether remove the tag or remove specific attributes/child elements.&lt;/p&gt;

&lt;p&gt;As we learned earlier, sanitizing removes suspicious code while keeping safe code. Angular automatically strips out unsafe attributes from safe elements. You will see a warning in the console letting you know Angular cleaned the content up. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fsxa7m2u76jkdicwv3nua.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fsxa7m2u76jkdicwv3nua.jpg" alt="Screenshot of DevTools console showing a warning. The warning says, 'WARNING: sanitizing HTML stripped some content, see https\://g.co/ng/security#xss" width="800" height="193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By handling values "the Angular way," our application is well protected against security woes! Success!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fvj8j7ecv15zg33u72bpe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fvj8j7ecv15zg33u72bpe.gif" alt="Giphy of Success baby meme" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Bypassing Angular's security checks
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;🚨 &lt;strong&gt;Here be dragons!&lt;/strong&gt; 🚨&lt;/p&gt;

&lt;p&gt;Be careful about bypassing the built-in security mechanism; if you need to, read this section carefully:  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What if you need to bind trusted values that Angular thinks are unsafe? You can mark values as trusted and bypass the security checks.&lt;/p&gt;

&lt;p&gt;Let's look at the example of the image with an error handler. Instead of the value coming from an agitator, let's say there's a legitimate need to bind the image with dynamic error handling.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sidenote&lt;/strong&gt; - there are better ways to handle images with error handling in Angular if your application doesn't need to be quite so dynamic. Consider using an image element and bind to &lt;code&gt;(error)&lt;/code&gt; instead, or even &lt;code&gt;HostListener&lt;/code&gt;. Or, there are many tutorial examples of handling it cleanly using a Directive. Indeed, there are lots of better options. You should always prefer the standard Angular way using Angular building blocks. The code will be way easier to support.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Back to the example, then. In the example above, we saw that the error handler didn't run. Angular stripped it out. We need to mark the code as trusted for the error code to run.&lt;/p&gt;

&lt;p&gt;Your component code might look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-trustworthy-image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;section [innerHTML]="html"
  `&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;TrustworthyImageComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;img src=1 onerror="alert('Doh!')"/&amp;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;You see the broken image in the browser, and no alert pops up.&lt;/p&gt;

&lt;p&gt;We can use the &lt;code&gt;DomSanitzer&lt;/code&gt; class in &lt;code&gt;@angular/platform-browser&lt;/code&gt;, to mark values as safe. The &lt;code&gt;DomSanitizer&lt;/code&gt; class has built-in sanitization methods for four types of contexts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HTML - binding to add more content like this &lt;code&gt;innerHTML&lt;/code&gt; image example&lt;/li&gt;
&lt;li&gt;Style - binding styles to add more flair to the site&lt;/li&gt;
&lt;li&gt;URL - binding URLs like when you want to navigate to an external site in an anchor tag&lt;/li&gt;
&lt;li&gt;Resource URL - binding URLs that load and run as code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To mark the value as trusted and safe to use, you can inject &lt;code&gt;DomSanitizer&lt;/code&gt; and use one of the following methods appropriate for the security context to return a value marked as safe.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;bypassSecurityHTML&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;&lt;code&gt;bypassSecurityScript&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bypassSecurityTrustStyle&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bypassSecurityTrustUrl&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bypassSecurityTrustResourceUrl&lt;/code&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These methods return the same input but are marked as trusted by wrapping it in a safe equivalent of the sanitization type.&lt;/p&gt;

&lt;p&gt;Let's see what this component looks like when we mark the HTML value as trusted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-trustworthy-image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;section [innerHTML]="html"
  `&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;TrustworthyImageComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;img src=1 onerror="alert('Doh!')"/&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;safeHtml&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SafeHtml&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="nx"&gt;sanitizer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DomSanitizer&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;safeHtml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sanitizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bypassSecurityTrustHtml&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;html&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;Now, if you view this in the browser, you'll see the broken image and an alert pop up. Success?? Maybe...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Filu1avd98i6yeg61jbep.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Filu1avd98i6yeg61jbep.gif" alt="Giphy of not sure if meme" width="333" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's look at an example with a resource URL, such as the DOM-based XSS example where we bind the URL of the &lt;code&gt;iframe&lt;/code&gt; source. &lt;/p&gt;

&lt;p&gt;Your component code might look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-video&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;iframe [src]="linky" width="800px" height="450px"
  `&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;VideoComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// pretend this is from an external source&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;linky&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;//videolink/embed/12345&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;Angular will stop you right there. 🛑&lt;/p&gt;

&lt;p&gt;You'll see an error in the console saying unsafe values can't be used in a resource URL. Angular recognizes you're trying to add a resource URL and is alarmed you're doing something dangerous. Resource URLs can contain legitimate code, so Angular can't sanitize it, unlike the comments we had above.&lt;/p&gt;

&lt;p&gt;If we are &lt;strong&gt;sure&lt;/strong&gt; our link is safe and trustworthy (highly debatable in this example, but we'll ignore that for a moment), we can mark the resource as trusted after we do some cleanup to make the resource URL safer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember, we should only use the &lt;code&gt;bypassSecurityTrust...&lt;/code&gt; methods if we know the value is trustworthy. You bypass the built-in security mechanisms and open yourself to security vulnerabilities!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of using the entire video URL based on the external party's API response, we'll construct the URL by defining the video host URL within our app and appending the video's ID that we get back from the external party's API response. This way, we aren't entirely reliant on a potentially untrustworthy value from a third party. Instead, we'll have some measure of ensuring we're not injecting malicious code into the URL. &lt;/p&gt;

&lt;p&gt;Then we'll mark the video URL as trusted and bind it in the template. Your &lt;code&gt;VideoComponent&lt;/code&gt; changes to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-video&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;iframe [src]="safeLinky" width="800px" height="450px"
  `&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;VideoComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// pretend this is from an external source&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;videoId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;12345&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;safeLinky&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SafeResourceUrl&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;sanitizer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DomSanitizer&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;safeLinky&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sanitizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bypassSecurityTrustResourceUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`//videolink/embed/&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;videoId&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you'll be able to show trailers of the K-Dramas on your site in an &lt;code&gt;iframe&lt;/code&gt; in a much safer way.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It can't be stressed enough. Ensure you trust the values before bypassing the out-of-the-box security protections you get from Angular!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Great! So we're done? Not quite. There are a couple of things to note.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use ahead-of-time (AOT) compilation for extra security
&lt;/h3&gt;

&lt;p&gt;Angular's AOT compilation has extra security measures for injection attacks like XSS. AOT compilation is highly recommended for production code and has been the default compilation method since Angular v9. Not only is it more secure, but it also improves performance.&lt;/p&gt;

&lt;p&gt;On the flip side, the other form of compilation is Just-in-time (JIT). JIT was the default for older versions of Angular. JIT compiles code for the browser on the fly, and this process skips Angular's built-in security protection, so stick with using AOT.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't concatenate strings to construct templates
&lt;/h3&gt;

&lt;p&gt;Angular trusts template code and only escapes values defined in the template using interpolation. So if you attempt something clever to circumvent the more common forms of defining the template for a component, you won't be protected. &lt;/p&gt;

&lt;p&gt;For example, you won't have Angular's built-in protections if you try to dynamically construct templates combining HTML with data using string concatenation or have an API whip up a payload with a template you somehow inject into the app. Your clever hacks with dynamic components might cause you security woes. &lt;/p&gt;

&lt;h3&gt;
  
  
  Beware of constructing DOM elements without using Angular templates
&lt;/h3&gt;

&lt;p&gt;Any funny business you might try using &lt;code&gt;ElementRef&lt;/code&gt; or &lt;code&gt;Renderer2&lt;/code&gt; is the perfect way to cause security issues. For example, you can pwn yourself if you try to do something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-yikes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div #whydothis&amp;gt;&amp;lt;/div&amp;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;YikesComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;AfterViewInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;whydothis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// pretend this is from an external source&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;attack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;img src=1 onerror="alert(&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;YIKES!&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;)"&lt;/span&gt;&lt;span class="dl"&gt;'&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&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;public&lt;/span&gt; &lt;span class="nf"&gt;ngAfterViewInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// danger below!&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;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&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;attack&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;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&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;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;innerHTML&lt;/span&gt;&lt;span class="dl"&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;attack&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;Something like this might be tempting in a fancy custom directive, but think again! Besides, interacting directly with the DOM like this isn't the best practice in Angular, even beyond any security issues it might have. It's always wise to prefer creating and using Angular templates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explicitly sanitize data
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;DomSanitizer&lt;/code&gt; class also has a method to sanitize values explicitly.&lt;/p&gt;

&lt;p&gt;Let's say you cook up a legitimate need to use &lt;code&gt;ElementRef&lt;/code&gt; or &lt;code&gt;Render2&lt;/code&gt; to build out the DOM in code. You can sanitize the value you add to the DOM using the method &lt;code&gt;sanitize()&lt;/code&gt;. The &lt;code&gt;sanitize()&lt;/code&gt; method takes two parameters, the security context for the sanitization and the value. The security context is an enumeration matching the security context listed previously.&lt;/p&gt;

&lt;p&gt;If we redo the &lt;code&gt;YikesComponent&lt;/code&gt; to explicitly sanitize, the code looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-way-better&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div #waybetter&amp;gt;&amp;lt;/div&amp;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;WayBetterComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;AfterViewInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;waybetter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// pretend this is from an external source&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;attack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;img src=1 onerror="alert(&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;YIKES!&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;)"&lt;/span&gt;&lt;span class="dl"&gt;'&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;sanitizer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DomSanitizer&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;public&lt;/span&gt; &lt;span class="nf"&gt;ngAfterViewInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&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;cleaned&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;sanitizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sanitize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SecurityContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HTML&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;attack&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;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&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;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;innerHTML&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cleaned&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;Now you'll have the image without the potentially dangerous code tagging along for the ride.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consider Trusted Types
&lt;/h3&gt;

&lt;p&gt;One more built-in security mechanism in Angular is setting up and using a Content Security Policy (CSP). CSPs are a specific HTTP security header we covered in the &lt;a href="https://developer.okta.com/blog/2022/07/06/spa-web-security" rel="noopener noreferrer"&gt;first post&lt;/a&gt; to help set up foundational security mechanisms.&lt;/p&gt;

&lt;p&gt;Angular has built-in support for defining policies for a CSP called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types" rel="noopener noreferrer"&gt;Trusted Types&lt;/a&gt;. Trusted Types are a great way to add extra XSS security guards to your Angular app but isn't supported across all the major browsers yet. If you are interested in learning more about setting up the Trusted Types CSP for SPAs, check out this great post from the Auth0 blog - &lt;a href="https://auth0.com/blog/securing-spa-with-trusted-types/" rel="noopener noreferrer"&gt;Securing SPAs with Trusted Types&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more about XSS, Trusted Types, and creating applications using Angular
&lt;/h2&gt;

&lt;p&gt;This series taught us about web security, common web attacks, and how Angular's built-in security mechanisms protect us from accidental attacks.&lt;/p&gt;

&lt;p&gt;If you liked this post, you might be interested in these links.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://angular.io/guide/security#security" rel="noopener noreferrer"&gt;Security documentation from Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/05/17/angular-microfrontend-auth" rel="noopener noreferrer"&gt;How to Build Micro Frontends Using Module Federation in Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/02/24/angular-async-config" rel="noopener noreferrer"&gt;Three Ways to Configure Modules in Your Angular App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/blog/defending-against-xss-with-csp/" rel="noopener noreferrer"&gt;Defending against XSS with CSP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/blog/securing-spa-with-trusted-types/" rel="noopener noreferrer"&gt;Securing SPAs with Trusted Types&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and subscribe to our &lt;a href="https://www.youtube.com/c/OktaDev/" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for more great tutorials. We'd also love to hear from you! Please comment below if you have any questions or want to share what tutorial you'd like to see next.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>security</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Protect Your Angular App From Cross-Site Request Forgery</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Tue, 26 Jul 2022 15:22:11 +0000</pubDate>
      <link>https://forem.com/oktadev/protect-your-angular-app-from-cross-site-request-forgery-2hho</link>
      <guid>https://forem.com/oktadev/protect-your-angular-app-from-cross-site-request-forgery-2hho</guid>
      <description>&lt;p&gt;Previously, I wrote about web security at a high level and the framework-agnostic ways to increase safety and mitigate vulnerabilities.&lt;/p&gt;

&lt;p&gt;Now, I want to dive a little deeper into the vulnerabilities. In this short post, we'll dive into &lt;strong&gt;C&lt;/strong&gt;ross-&lt;strong&gt;S&lt;/strong&gt;ite &lt;strong&gt;R&lt;/strong&gt;equest &lt;strong&gt;F&lt;/strong&gt;orgery (CSRF) and look at the built-in help you get when using Angular.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-Site Request Forgery (CSRF) protection
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://developer.okta.com/blog/2022/07/08/spa-web-securty-csrf-xss#validate-requests-for-authenticity-to-mitigate-csrf" rel="noopener noreferrer"&gt;previous post&lt;/a&gt;, you learned how an attack for CSRF occurs when an agitator uses your active session for a trusted site to perform unauthorized actions. We also learned there's built-in support from browsers to mitigate attacks with &lt;code&gt;SameSite&lt;/code&gt; attributes on cookies, validating the authenticity of the request on the backend, and potentially having the frontend send a CSRF token to the backend for every request.&lt;/p&gt;

&lt;p&gt;The mitigation strategies primarily require server-side work, except for that game of CSRF token sending, where the client needs to send the token back in a way the backend can validate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F7ior81pkjmvh56o2a5vd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F7ior81pkjmvh56o2a5vd.gif" alt="Giphy of a dog picking up mail from the postal worker" width="199" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When using CSRF tokens, it's essential to tie the token to the user's session so that the backend can validate the request. The most common ways are through the patterns called &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#synchronizer-token-pattern" rel="noopener noreferrer"&gt;Synchronizer Token Pattern&lt;/a&gt; and &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie" rel="noopener noreferrer"&gt;Double Submit Cookie&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Synchronizer Token Pattern
&lt;/h3&gt;

&lt;p&gt;The Synchronizer Token Pattern requires the backend to store the user's session information and match it up with the CSRF token for validity. This pattern can be used with SPAs but is a better match for web apps that use forms with post methods for requests, such as:&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;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://myfavekdramas.com/fave-form"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;What is your favorite K-Drama?&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Save my favorite K-Drama&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Submitting this form POSTs to &lt;code&gt;https://myfavekdramas.com/fave-form&lt;/code&gt; using the &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt; content type. CSRF is especially susceptible when using non-JSON data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Double Submit Cookie Pattern
&lt;/h3&gt;

&lt;p&gt;Sadly, this pattern doesn't involve double the cookies—it's a dual submission. Sad news indeed for chocolate-chip cookie fans. 🍪🍪 😢 But the good news is the Double Submit Cookie Pattern doesn't require the backend to track the user's session to the CSRF token. &lt;/p&gt;

&lt;p&gt;In this pattern, the CSRF token is a separate cookie from the user's session identifier. The client sends the CSRF token in every request, and the backend validates that the CSRF token cookie and the token in the request values match. This pattern is more common for SPAs.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSRF support in Angular
&lt;/h2&gt;

&lt;p&gt;Angular has built-in support for a flavor of the Double Submit Cookie Pattern, where the CSRF token is automatically added as an HTTP header for every backend request once you have a CSRF token in a cookie. Nice!&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;HttpClientXsrfModule&lt;/code&gt; automatically adds an interceptor for your HTTP requests. The interceptor grabs the CSRF token from a session cookie named &lt;code&gt;XSRF-TOKEN&lt;/code&gt; and adds the token value to outgoing requests in the HTTP header named &lt;code&gt;X-XSRF-TOKEN&lt;/code&gt;. Then your backend is responsible for verifying the values for the cookie and HTTP header match.&lt;/p&gt;

&lt;p&gt;To add this handy helper, add &lt;code&gt;HttpClientModule&lt;/code&gt; and the &lt;a href="https://angular.io/api/common/http/HttpClientXsrfModule" rel="noopener noreferrer"&gt;&lt;code&gt;HttpClientXsrfModule&lt;/code&gt;&lt;/a&gt; to your module's &lt;code&gt;imports&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;If you don't like the default names, you have the option of configuring the names of the cookie and HTTP header like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&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;HttpClientModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;HttpClientXsrfModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withOptions&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;cookieName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pecan-Sandies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Top-Of-Page&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;h2&gt;
  
  
  Learn more about CSRF and creating applications using Angular
&lt;/h2&gt;

&lt;p&gt;Watch for the fourth and final post in this series, as we dive into Cross-Site Scripting (XSS) and learn how Angular's built-in security mechanisms protect us.&lt;/p&gt;

&lt;p&gt;If you liked this post, you might be interested in these links.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://angular.io/guide/http#security-xsrf-protection" rel="noopener noreferrer"&gt;Security: XSRF protection documentation from Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/05/17/angular-microfrontend-auth" rel="noopener noreferrer"&gt;How to Build Micro Frontends Using Module Federation in Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/02/24/angular-async-config" rel="noopener noreferrer"&gt;Three Ways to Configure Modules in Your Angular App&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and subscribe to our &lt;a href="https://www.youtube.com/c/OktaDev/" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for more great tutorials. We'd also love to hear from you! Please comment below if you have any questions or want to share what tutorial you'd like to see next.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>security</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Defend Your SPA From Common Web Attacks</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Thu, 21 Jul 2022 14:35:29 +0000</pubDate>
      <link>https://forem.com/oktadev/defend-your-spa-from-common-web-attacks-2ibo</link>
      <guid>https://forem.com/oktadev/defend-your-spa-from-common-web-attacks-2ibo</guid>
      <description>&lt;p&gt;This is the second post in a series about web security for SPAs. In the last post, we laid the groundwork for thinking about web security and applying security mechanisms to our application stack. We covered the &lt;a href="https://owasp.org/Top10/" rel="noopener noreferrer"&gt;OWASP Top Ten&lt;/a&gt;, using secure data communication with SSL/TLS, using security headers to help enhance built-in browser mechanisms, keeping dependencies updated, and safeguarding cookies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Frtolnzzr3fnsft5e0idc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Frtolnzzr3fnsft5e0idc.gif" alt="Animated gif of a padlock inside a shield" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ready to continue and make your SPA safer? This post will use the concepts we introduced to banish some well-known web vulnerabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice data cleanliness to mitigate XSS
&lt;/h2&gt;

&lt;p&gt;Cross-Site Scripting (XSS) is a vulnerability that continues to plague web developers. This vulnerability is a type of injection attack and is so common that it's &lt;a href="https://owasp.org/Top10/A03_2021-Injection/" rel="noopener noreferrer"&gt;number 3 on the OWASP Top Ten list&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;How does this vulnerability work? In short, XSS happens when code pollutes data, and you don't implement safeguards. &lt;/p&gt;

&lt;p&gt;Ok, fine, but what does that mean? A classic example is a website that allows user input, like adding comments or reviews. Suppose the input form accepts anything the user types in and doesn't appropriately safeguard that user input before storing and displaying it to other users. In that case, it's at risk for XSS. &lt;/p&gt;

&lt;p&gt;Imagine an overly dramatic but otherwise innocent scenario like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;A website allows you to add comments about your favorite K-Drama.&lt;/li&gt;
&lt;li&gt;An agitator adds the comment &lt;code&gt;&amp;lt;script&amp;gt;alert('Crash Landing on You stinks!');&amp;lt;/script&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;That terrible comment saves as is to the database.&lt;/li&gt;
&lt;li&gt;A K-Drama fan opens the website.&lt;/li&gt;
&lt;li&gt;The terrible comment is added to the website, appending the &lt;code&gt;&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; tag to the DOM.&lt;/li&gt;
&lt;li&gt;The K-Drama fan is outraged by the JavaScript alert saying their favorite K-Drama stinks.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, this is obviously awful. Least of all because we all know "&lt;a href="https://www.imdb.com/title/tt10850932/" rel="noopener noreferrer"&gt;Crash Landing on You&lt;/a&gt;" is, in fact, wonderful. Also, this scenario exposes your website to the possibility of a colossal breach in which an injection attack can do all sorts of bad things. With JavaScript, the attack could grab cookies, dig around your browser's local storage for authentication information, access your file system, make calls to other sites, and do even more harm.&lt;/p&gt;

&lt;p&gt;In this case, we've show an example very clearly using a &lt;code&gt;&amp;lt;script&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; tag to make it easier for us to talk about, but an attack can use anything that runs JavaScript, such as adding an HTML element with JS embedded in the attribute, adding JS to resource URLs, embedding JS into CSS, and so forth. This is the true stuff of nightmares!&lt;/p&gt;

&lt;p&gt;How do we avoid these sorts of shenanigans? There are a few different defensive tactics, but the main one is to ensure you practice good data hygiene through &lt;strong&gt;escaping&lt;/strong&gt; and &lt;strong&gt;sanitizing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Escaping&lt;/strong&gt; refers to replacing certain specific characters in HTML so they are read as text strings, such as replacing &lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;amp;lt;b&amp;amp;gt;&lt;/code&gt;). When you escape, the browser no longer treats the value as part of the code. It's simply text or data. Although we're talking XSS here, escaping is a good practice in general as it will protect you against SQL injection, a different type of injection attack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fbov4upf5w8v5et5y6v5g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbov4upf5w8v5et5y6v5g.png" alt="A cartoon showing a person on the phone. The conversation goes like this " width="666" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-- &lt;cite&gt;&lt;a href="https://xkcd.com/327/" rel="noopener noreferrer"&gt;xkcd&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sanitizing&lt;/strong&gt; removes code that might be malicious, while preserving some safe HTML tags. The primary use case for choosing to &lt;em&gt;sanitize&lt;/em&gt; instead of to &lt;em&gt;escape&lt;/em&gt; the code is when you want to allow markup to display, like if you have a rich text editor on your website.&lt;/p&gt;

&lt;p&gt;There's a lot more to discuss regarding cross-site scripting, including types of XSS and mitigation technique specifics, so keep an eye out for a follow-up post with more details, including the built-in XSS security mechanisms provided in some SPA frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dive into XSS
&lt;/h3&gt;

&lt;p&gt;Can't wait to read more about XSS? Check out these resources that cover how cross-site scripting works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/books/api-security/sanitizing/" rel="noopener noreferrer"&gt;API Security book chapter on Sanitizing Data by Okta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://portswigger.net/web-security/cross-site-scripting" rel="noopener noreferrer"&gt;Cross-site scripting resource from Port Swigger Web Security Academy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Validate requests for authenticity to mitigate CSRF
&lt;/h2&gt;

&lt;p&gt;Cross-Site Request Forgery (CSRF) is another well-known vulnerability in the &lt;a href="https://owasp.org/Top10/A01_2021-Broken_Access_Control/" rel="noopener noreferrer"&gt;top spot of the OWASP Top Ten, Broken Access Control&lt;/a&gt;. CSRF allows attackers to exploit your identity to perform unauthorized actions. Sounds pretty bad, right? Well, yup, you're correct.&lt;/p&gt;

&lt;p&gt;The exploit works like this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;You log in to the K-Drama site to upvote some recent shows you watched.&lt;/li&gt;
&lt;li&gt;Then, in a loss of judgment, you open a spam email and click the link to transfer money to an agitator claiming to be your long lost high school sweetheart. (What were you thinking!) &lt;/li&gt;
&lt;li&gt;The link takes you to a malicious site with a hidden form embedded within it.&lt;/li&gt;
&lt;li&gt;The hidden form sends an HTTP POST request with terrible comments to the K-Drama site along with the active session cookie. &lt;/li&gt;
&lt;li&gt;Since you have an active authenticated session on the K-Drama site, the POST completes as if you were the one adding terrible comments about "Hospital Playlist"!&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Luckily in this example, the unauthorized action isn't irreversible or devastating. You can delete the terrible comments, and you can explain how it wasn't really you who posted such comments to horrified "&lt;a href="https://www.imdb.com/title/tt11769304/" rel="noopener noreferrer"&gt;Hospital Playlist&lt;/a&gt;" fans. However, you can see how dangerous and malicious this exploit would be if the target was something fundamental like a bank!&lt;/p&gt;

&lt;p&gt;The only way to mitigate against CSRF is to ensure the request is legitimate.&lt;/p&gt;

&lt;p&gt;Fortunately, we already have some tools and actions at our disposal that we covered previously, such as: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prefer tokens in HTTP headers for authenticated HTTP calls and ideally store those tokens in-memory.&lt;/li&gt;
&lt;li&gt;Configure tight CORS controls.&lt;/li&gt;
&lt;li&gt;Protect your cookies!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These mechanisms are so good that some say &lt;a href="https://scotthelme.co.uk/csrf-is-dead/" rel="noopener noreferrer"&gt;there's nothing more you need to do for SPAs&lt;/a&gt;! &lt;/p&gt;

&lt;p&gt;However, CSRF relies on your backend not completing due diligence to verify the authenticity of the requests and allowing non-JSON payloads. Hackers are very clever, and you may need to allow &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; payloads in your backend, so you may need extra safeguards. When you do need extra guards, you can add a unique CSRF token for communication between your frontend and backend. The backend needs to verify standard authentication and authorization safeguards and verify the CSRF token's legitimacy. &lt;/p&gt;

&lt;p&gt;The token is generated by the backend and sent to the frontend. The frontend then uses the token in subsequent calls to the backend by adding it as a custom HTTP header.&lt;/p&gt;

&lt;p&gt;For SPAs, getting that CSRF token from the server is the difficult part. In traditional web apps, it's not a problem. But for SPAs, you don't call your back-end API until after you load the application. You also want CSRF protection before logging in if you're not delegating authentication to a third-party authentication provider. 😎&lt;/p&gt;

&lt;p&gt;The recommendation is to have your client call an endpoint on your backend to get the CSRF token. The endpoint &lt;strong&gt;must&lt;/strong&gt; be super vigilant about confirming the caller's origin and keeping that CORS allowlist very strict.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dive deeper into CSRF
&lt;/h3&gt;

&lt;p&gt;There are a lot of browser protections that help us mitigate CSRF. Check out these links if you want to learn more about CSRF.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://auth0.com/blog/cross-site-request-forgery-csrf/" rel="noopener noreferrer"&gt;Prevent Cross-Site Request Forgery (CSRF) Attacks by Auth0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html" rel="noopener noreferrer"&gt;Cross-Site Request Forgery Prevention Cheat Sheet by OWASP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pillarjs/understanding-csrf" rel="noopener noreferrer"&gt;Understanding CSRF from the Express team&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Learn more about common web attacks
&lt;/h2&gt;

&lt;p&gt;Stay tuned for the next post in this series as we dive deeper into CSRF and learn how Angular helps protect against it.&lt;/p&gt;

&lt;p&gt;Ready to learn more? Check out out the following resources.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/02/08/cookies-vs-tokens" rel="noopener noreferrer"&gt;A Comparison of Cookies and Tokens for Secure Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/blog/cross-site-scripting-xss/" rel="noopener noreferrer"&gt;Defend Your Web Apps from Cross-Site Scripting (XSS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/IndexTopTen.html" rel="noopener noreferrer"&gt;OWASP Top Ten 2021: Related Cheat Sheets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and subscribe to our &lt;a href="https://www.youtube.com/c/OktaDev/" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for more great tutorials. We'd also love to hear from you! If you have any questions or want to share what tutorial you'd like to see next, please comment below.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Defend Your SPA From Security Woes</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Tue, 19 Jul 2022 14:43:43 +0000</pubDate>
      <link>https://forem.com/oktadev/defend-your-spa-from-security-woes-1fg2</link>
      <guid>https://forem.com/oktadev/defend-your-spa-from-security-woes-1fg2</guid>
      <description>&lt;p&gt;There's a lot of information floating out there about web security. But when I read through the material, I noticed some information wasn't up to date, or it was written specifically for traditional server-rendered web applications, or the author recommended anti-patterns. In a series of posts, I will cover web security concerns that all web devs should be aware of, emphasizing client-side applications, namely Single Page Applications (SPAs). Furthermore, I'm not going to get into the nitty-gritty of web security, cryptography, and networking.  Instead, I'll focus on the main takeaways and high-level to-do lists. I'll also provide links to resources where you can dive in deeper.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F1c11gzorfqzfckrtlwvb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F1c11gzorfqzfckrtlwvb.gif" alt="Animated gif of a security shield blocking a computer from attacks" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So why do we worry about web security anyway? When we have vulnerabilities in our applications, it's an avenue for exploitation by bad actors. In the wrong hands, exploiting the vulnerabilities can cause risks to your application, data, reputation, and bottom line. In the words of my coworker &lt;a href="https://developer.okta.com/blog/authors/aaron-parecki/" rel="noopener noreferrer"&gt;Aaron Parecki&lt;/a&gt;, it all boils down to one thing—liability. And we don't want to expose ourselves, our applications, and our companies to liability. If you feel threatened, it's a good time to read on and identify how to harden your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the OWASP Top 10 to identify the most common vulnerabilities
&lt;/h2&gt;

&lt;p&gt;If you're new to thinking about security, you may not have heard of the &lt;a href="https://owasp.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;O&lt;/strong&gt;pen &lt;strong&gt;W&lt;/strong&gt;eb &lt;strong&gt;A&lt;/strong&gt;pplication &lt;strong&gt;S&lt;/strong&gt;ecurity &lt;strong&gt;P&lt;/strong&gt;roject&lt;/a&gt; (OWASP). OWASP is a group that focuses on making the web a safer place. They maintain and publish a list of the most common web vulnerabilities named the "&lt;a href="https://owasp.org/www-project-top-ten/" rel="noopener noreferrer"&gt;OWASP Top Ten&lt;/a&gt;" and have a new top ten list for 2021; their infographic shows how the top web vulnerabilities have changed from 2017 to 2021.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fi6vo4th27syoy2rv4q4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fi6vo4th27syoy2rv4q4b.png" alt="OWASP Top 10 for 2021 shows the following vulnerabilities in order: Broken Access Control, Cryptographic Failures, Injection, Insecure Design, Security Misconfiguration, Vulnerable and Outdated Components, Identification and Authentication Failures, Software and Data Integrity Failures, Security Logging and Monitoring Failures, and Server-Side Request Forgery" width="800" height="220"&gt;&lt;/a&gt;&lt;br&gt;
&lt;cite&gt;&lt;a href="https://owasp.org/Top10/" rel="noopener noreferrer"&gt;CC-by Open Web Application Security Project&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;As this is a list of web vulnerabilities, the entire list is pertinent to our work as web developers. However, a few critical vulnerabilities call for extra attention, and some vulnerabilities are less susceptible when the front-end is a SPA with a JSON-based backend API.&lt;/p&gt;

&lt;p&gt;We will cover some of these vulnerabilities specifically, but I'll also list general things to keep in mind that feed into the vulnerabilities listed here.&lt;/p&gt;


&lt;h2&gt;
  
  
  Leverage your browser and security headers
&lt;/h2&gt;

&lt;p&gt;First, we need to set the stage for part of our vulnerability mitigation strategy by bringing up security headers. Modern browsers (buh-bye Internet Explorer!!) have a lot of security mechanisms already built in. We have to leverage the built-in security mechanisms and can enhance them with additional security headers. Security headers are HTTP response headers that provide instructions on how the browser should behave. They are defined on your web server.&lt;/p&gt;

&lt;p&gt;There are quite a few security headers that we can apply. Something to note, SPAs are unique, so not all security headers apply in the same way as they would for a traditional server-rendered web application. I'll call out the security headers that you'll want to use when we discuss how to mitigate a specific vulnerability. &lt;/p&gt;
&lt;h3&gt;
  
  
  Dive deeper into security headers
&lt;/h3&gt;

&lt;p&gt;Here are some great resources to learn more about security headers. Figuring out how to configure the security headers can be esoteric. I like these posts that are short and offer actionable steps to configure security headers. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2021/10/18/security-headers-best-practices" rel="noopener noreferrer"&gt;An Overview of Best Practices for Security Headers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP's HTTP Security Response Headers Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.dev/security-headers/" rel="noopener noreferrer"&gt;Web.dev's Security headers quick reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Securely transport data using TLS/SSL
&lt;/h2&gt;

&lt;p&gt;Using HTTPS should be the undisputed standard, but there are legacy systems where applications don't use HTTPS. It's essential to use the &lt;em&gt;secure&lt;/em&gt; hypertext transfer protocol; after all, the HTTPS acronym is appropriately derived from &lt;strong&gt;H&lt;/strong&gt;ypertext &lt;strong&gt;T&lt;/strong&gt;ransfer &lt;strong&gt;P&lt;/strong&gt;rotocol &lt;strong&gt;S&lt;/strong&gt;ecure. And it's essential to be secure across your &lt;em&gt;entire&lt;/em&gt; stack, not just when serving the front-end site (don't ask me how I know this can be a thing). &lt;/p&gt;

&lt;p&gt;When you don't use an up-to-date &lt;strong&gt;T&lt;/strong&gt;ransport &lt;strong&gt;L&lt;/strong&gt;ayer &lt;strong&gt;S&lt;/strong&gt;ecurity within your application system, you expose yourself to &lt;a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack" rel="noopener noreferrer"&gt;meddler-in-the-middle attacks (MITM)&lt;/a&gt;. In this type of attack, agitators intercept communication between unsecured systems to siphon data or impersonate communicating parties. &lt;/p&gt;

&lt;p&gt;You might think this callout to use HTTPS is unnecessary because it's such a standard for hosting web apps, but &lt;a href="https://owasp.org/Top10/A02_2021-Cryptographic_Failures/" rel="noopener noreferrer"&gt;cryptographic failures that cause insecure communication are the second most common vulnerability in the OWASP Top Ten&lt;/a&gt;! Note that it's not enough to slap any old mechanism for HTTPS on your web server. You want a &lt;em&gt;recent&lt;/em&gt; version of TLS. Your cloud providers might even force you to upgrade if your TLS version is old, which is good!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fooed1oczslo3c80n3q7k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fooed1oczslo3c80n3q7k.png" alt="Cartoon with one character saying " width="337" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-- &lt;cite&gt;&lt;a href="https://xkcd.com/2634/" rel="noopener noreferrer"&gt;xkcd&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;What's the takeaway here? Specifically, you'll want to make sure you have functioning certificates, ensure you're using the latest version of TLS, and make sure you use SSL/TLS over your &lt;em&gt;entire stack&lt;/em&gt;. All of these steps might already be covered by your cloud hosting provider. You should also verify you've added the &lt;strong&gt;HTTP Strict Transport Security (HSTS)&lt;/strong&gt; security header to the web server, which adds an extra layer of security beyond HTTPS redirection.&lt;/p&gt;
&lt;h3&gt;
  
  
  Dive deeper into transport layer security
&lt;/h3&gt;

&lt;p&gt;Check out these resources if you want to read more about Transport Layer Security and how to set up HTTPS redirection and HTST.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/books/api-security/tls/" rel="noopener noreferrer"&gt;Okta's API Security book chapter on Transport Layer Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP's Transport Layer Protection Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infosec.mozilla.org/guidelines/web_security#transport-layer-security-tlsssl" rel="noopener noreferrer"&gt;TLS Guidelines from MDN&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://letsencrypt.org/getting-started/" rel="noopener noreferrer"&gt;Getting started with HTTPS and certificates with Let's Encrypt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Keep your framework and external dependencies up to date
&lt;/h2&gt;

&lt;p&gt;You knew this was coming, even though we might lament the work involved to stay up to date. The advice to update your dependencies sounds like "Don't forget to floss," but it's essential (just like flossing). &lt;a href="https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/" rel="noopener noreferrer"&gt;Vulnerable and outdated components take the sixth spot in the OWASP Top Ten list&lt;/a&gt;. And there were some significant vulnerabilities from dependencies in the news recently. So you know deep down that burying your head in the sand is not a good action plan.&lt;/p&gt;

&lt;p&gt;It's important to note that we should update outdated components &lt;strong&gt;and&lt;/strong&gt; ensure we don't accidentally depend on a vulnerable dependency. We should pin dependency versions in our &lt;code&gt;package.json&lt;/code&gt; and then generate and enforce the use of a lock file. That means running &lt;code&gt;npm ci&lt;/code&gt; instead of &lt;code&gt;npm i&lt;/code&gt; to force the exact versions defined in the &lt;code&gt;package-lock.json&lt;/code&gt;. If you use Yarn, you will use &lt;code&gt;yarn install --frozen-lockfile&lt;/code&gt;. This way, updating versions is an intentional act.&lt;/p&gt;

&lt;p&gt;That's it. Just do it. It's important. Outdated components are a source of &lt;em&gt;liability&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Dive deeper into keeping your components up to date
&lt;/h3&gt;

&lt;p&gt;Check out a step-by-step guide on dependency management for JavaScript developers by the OWASP team - &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/NPM_Security_Cheat_Sheet.html" rel="noopener noreferrer"&gt;NPM Security best practices&lt;/a&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Load resources securely
&lt;/h2&gt;

&lt;p&gt;Cross-origin resources are a particular concern for SPAs; this refers to resources your web app uses that are not hosted on the same origin as your web application. When all the resources the front-end needs are available through the same origin, we have confidence that the resources are secure. Hopefully, we're not pwning ourselves! At least not intentionally, right?!&lt;/p&gt;

&lt;p&gt;A typical pattern for setting up URLs for SPA communicating to back-end APIs might look like the following, where your front-end is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://myfavekdramas.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the back-end API URL is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://apis.myfavekdramas.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the API URL is a subdomain, so the request is cross-origin. Most browsers (once again BUH-BYE Internet Explorer!) protect us by allowing only specific cross-origin requests. We can configure resource access by enabling &lt;strong&gt;C&lt;/strong&gt;ross-&lt;strong&gt;o&lt;/strong&gt;rigin &lt;strong&gt;R&lt;/strong&gt;esource &lt;strong&gt;S&lt;/strong&gt;haring (CORS).&lt;/p&gt;

&lt;p&gt;Between your production environment setup resembling the above URLs, and local development using different ports for your front-end and back-end, you might be tempted to enable CORS to allow all sorts of requests. Unlike other security measures covered in this post, your browser already protects you in the strictest way possible. Enabling CORS &lt;em&gt;loosens&lt;/em&gt; that restriction.&lt;/p&gt;

&lt;p&gt;So the advice is to enable CORS appropriately with considered use of allowlists. Use proxies as appropriate (such as for local development). The concept of least privilege applies here too, and keeping a tight lid on things helps mitigate security vulnerabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dive into cross-origin resource sharing
&lt;/h3&gt;

&lt;p&gt;Want to understand better when CORS rules apply or how to set up the allowlist rules? Read these resources for a deep dive.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2021/08/02/fix-common-problems-cors" rel="noopener noreferrer"&gt;Fixing Common Problems with CORS and JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" rel="noopener noreferrer"&gt;MDN CORS Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/blog/cors-tutorial-a-guide-to-cross-origin-resource-sharing/" rel="noopener noreferrer"&gt;Auth0's CORS Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Protect your cookies from theft
&lt;/h2&gt;

&lt;p&gt;Really, this advice is applicable outside of web development too. But since we're talking about web development in this post, we'll skip mitigation strategies about protecting your physical cookies from marauders and focus again on security headers.&lt;/p&gt;

&lt;p&gt;Cookies can contain all sorts of goodies, such as chocolate chips and the tidbits of data that agitators love to have! Current authentication best practices favor using in-browser memory or web workers for authentication tokens over cookies, and cookies should never be used for secrets, but there might still be sensitive information stored in cookies. To help protect cookies, we can use attributes.&lt;/p&gt;

&lt;p&gt;Cookies should be temporary. In particular, cookies with sensitive information should be as short-lived as possible. When you or your back-end bakes up a cookie, adding the attribute &lt;code&gt;Max-Age&lt;/code&gt; defines the longevity of the cookie. &lt;/p&gt;

&lt;p&gt;There are some more attributes you can bake in! Adding the &lt;code&gt;httpOnly&lt;/code&gt; attribute means the browser only sends a cookie for HTTP requests, and JavaScript won't be able to access cookies. Setting the &lt;code&gt;httpOnly&lt;/code&gt; attribute is an excellent first step to guarding your cookies against a malicious script that can read your cookies.&lt;/p&gt;

&lt;p&gt;Having the &lt;code&gt;httpOnly&lt;/code&gt; attribute means that JavaScript can't access the cookie, but it doesn't mean your browser carefully curates &lt;strong&gt;which&lt;/strong&gt; cookies to send to each HTTP request! It just sends them all, resulting in the possibility of a vulnerability!&lt;/p&gt;

&lt;p&gt;This is where the &lt;code&gt;SameSite&lt;/code&gt; attribute comes into play. You can control when cookies should be sent by using the &lt;code&gt;SameSite&lt;/code&gt; attribute and setting one of 3 values:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Strict&lt;/code&gt; - only send cookies if they are going to the same site that requested them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Lax&lt;/code&gt; - only send cookies when the user is navigating to the origin site. (This is the default behavior now for Chromium-based browsers.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;None&lt;/code&gt; - send the cookies to everyone, everywhere. As a safeguard for your generous behavior, which is concerning to the browser, you're also required to add the &lt;code&gt;Secure&lt;/code&gt; attribute.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the &lt;code&gt;SameSite&lt;/code&gt; attribute set, you can no longer have a scenario like this&lt;br&gt;
&lt;a href="https://media2.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%2Fp894a88r4sjhdiogs6n3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fp894a88r4sjhdiogs6n3.gif" alt="Giphy of multiple hands holding out cookies to Cookie Monster. Cookie Monster grabs and eats them all." width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Be thoughtful about cookies and apply principles of least privilege. Safeguarding cookies is a big step in mitigating other vulnerabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dive deeper into cookie guarding
&lt;/h3&gt;

&lt;p&gt;Learn more about protecting your cookies by checking out these fantastic resources.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web.dev/samesite-cookies-explained/" rel="noopener noreferrer"&gt;web.dev's SameSite cookies explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite" rel="noopener noreferrer"&gt;MDN's SameSite cookies web docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Learn more about web security
&lt;/h2&gt;

&lt;p&gt;Stay tuned for the next post in this series as we learn about two well-known web security attacks, along with mitigation techniques using what we covered here.&lt;/p&gt;

&lt;p&gt;Can't wait to learn more? Check out out the following resources.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/05/09/beginners-app-sec" rel="noopener noreferrer"&gt;A Beginner's Guide to Application Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2019/04/11/site-security-cloudflare-netlify" rel="noopener noreferrer"&gt;How to Configure Better Web Site Security with Cloudflare and Netlify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2020/03/23/microservice-security-patterns" rel="noopener noreferrer"&gt;Security Patterns for Microservice Architectures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/blog/security-and-web-development/" rel="noopener noreferrer"&gt;Security and Web Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/IndexTopTen.html" rel="noopener noreferrer"&gt;OWASP Top Ten 2021: Related Cheat Sheets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and subscribe to our &lt;a href="https://www.youtube.com/c/OktaDev/" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for more great tutorials. We'd also love to hear from you! If you have any questions or want to share what tutorial you'd like to see next, please comment below.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Secure and Deploy Micro Frontends with Angular</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Wed, 25 May 2022 15:01:30 +0000</pubDate>
      <link>https://forem.com/oktadev/secure-and-deploy-micro-frontends-with-angular-1b3p</link>
      <guid>https://forem.com/oktadev/secure-and-deploy-micro-frontends-with-angular-1b3p</guid>
      <description>&lt;p&gt;Micro frontends continue to gain interest and traction in front-end development. The architecture models the same concept as micro services - as a way to decompose monolithic front-end applications. And just like with micro services, micro frontends have complexities to manage.&lt;/p&gt;

&lt;p&gt;This post is part two in a series about building an e-commerce site with Angular using micro frontends. We use Webpack 5 with Module Federation to wire the micro frontends together, demonstrate sharing authenticated state between the different front ends, prepare for deployment using dynamic module loading, and deploy it all to &lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;'s free hosting plan. &lt;/p&gt;

&lt;p&gt;In this second post, we're building on the site we created in part one, &lt;a href="https://developer.okta.com/blog/2022/05/02/angular-microfrontend-auth" rel="noopener noreferrer"&gt;How to Build Micro Frontends Using Module Federation in Angular&lt;/a&gt;. &lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/oktadev" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F129%2F9284e7ae-5b8a-49ab-89de-0e5ebe85847b.jpg" alt="Okta" width="800" height="800"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F10521%2Fbb518cd1-0284-4059-bde1-c64ead162ff2.png" alt="" width="512" height="512"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/oktadev/how-to-build-micro-frontends-using-module-federation-in-angular-4ib2" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How to Build Micro Frontends Using Module Federation in Angular&lt;/h2&gt;
      &lt;h3&gt;Alisa for Okta ・ May 24 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#angular&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#frontend&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Let's add dynamic module loading to our cupcake e-commerce site, secure unprotected routes, and set up the site for deployment in Vercel, a service designed to improve the front-end development workflow. 🎉&lt;/p&gt;

&lt;p&gt;In the end, you'll have an app that looks like this publicly available through Vercel:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fm2ihmvegzehe2eb9tst1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fm2ihmvegzehe2eb9tst1.gif" alt="Animated gif showing the final project with micro frontends that handle the cupcake shopping basket, authentication, and profile information" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node&lt;/a&gt; This project was developed using Node v16.14 with npm v8.5 &lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular.io/cli" rel="noopener noreferrer"&gt;Angular CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub Account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Vercel Account&lt;/a&gt; connected through your GitHub credentials for automating deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Review the Angular micro-frontends project using Webpack and Module Federation
&lt;/h2&gt;

&lt;p&gt;Let's start by refreshing our memories—dust off your project from the &lt;a href="https://developer.okta.com/blog/2022/05/17/angular-microfrontend-auth" rel="noopener noreferrer"&gt;first post&lt;/a&gt;. Just like last time, we'll need both IDE and the terminal. &lt;/p&gt;

&lt;p&gt;We have the host application, &lt;code&gt;shell&lt;/code&gt;, and two micro-frontend remotes, &lt;code&gt;mfe-basket&lt;/code&gt; and &lt;code&gt;mfe-profile&lt;/code&gt;. We're using &lt;code&gt;@angular-architects/module-federation&lt;/code&gt; to help facilitate the Module Federation plugin configuration. The cupcake basket functionality code resides in the shared library, and we share authenticated state using Okta's SDKs. &lt;/p&gt;

&lt;p&gt;Serve all of the Angular applications in the project by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run run:all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When you run the project, you should see all the beautiful cupcakes this store sells. You'll be able to sign in, view your profile, add items to your basket, view your cupcake basket, and sign out. All the basics for handling your sweet treat needs!  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If you want to skip the first post and follow along with this tutorial, you can clone the code sample repo to get going. You will be missing quite a bit of context, though. Use the following commands in this case:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--branch&lt;/span&gt; &lt;span class="nb"&gt;local &lt;/span&gt;https://github.com/oktadev/okta-angular-microfrontend-example.git
npm ci
npm run run:all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You'll need to follow the instructions on creating the Okta application and updating the code with your Okta domain and client ID.&lt;/p&gt;
&lt;h2&gt;
  
  
  Dynamic loading of micro-frontend remotes
&lt;/h2&gt;

&lt;p&gt;So far, we've been serving the cupcake micro-frontend website using the npm script &lt;code&gt;run:all&lt;/code&gt;, which serves all three applications at once. Let's see what happens if we only try serving the host application. Stop serving the site, run &lt;code&gt;ng serve shell&lt;/code&gt; to serve the default application, &lt;code&gt;shell&lt;/code&gt;, and open the browser.&lt;/p&gt;

&lt;p&gt;When you navigate to &lt;code&gt;http://localhost:4200&lt;/code&gt;, you see a blank screen and a couple of console errors. The console errors happen because &lt;code&gt;shell&lt;/code&gt; can't find the micro-frontend remotes at ports 4201 and 4202. 👀&lt;/p&gt;

&lt;p&gt;These errors mean the host is loading the micro frontends upon initialization of the host, not upon route change like you might think based on configuring a lazy-loaded route in the routing module. Doh!&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;@angular-architects/module-federation&lt;/code&gt; library's &lt;code&gt;loadRemoteModule()&lt;/code&gt; method, we can dynamically load the micro-frontend remotes upon route change with a few quick changes.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;projects/shell/src/app/app-routing.module.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The function we pass into the &lt;code&gt;loadChildren&lt;/code&gt; property for the lazy-loaded routes changes to using &lt;code&gt;loadRemoteModule()&lt;/code&gt;. Update your routes array to match the code below.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;loadRemoteModule&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="s1"&gt;@angular-architects/module-federation&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;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProductsComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;basket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadChildren&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="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;remoteEntry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`http://localhost:4201/remoteEntry.js`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;exposedModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BasketModule&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadChildren&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="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;remoteEntry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`http://localhost:4202/remoteEntry.js`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;exposedModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ProfileModule&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OktaCallbackComponent&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;Now that you're loading the remotes within the route definitions, you no longer need to define the remote URI in the &lt;code&gt;projects/shell/webpack.config.js&lt;/code&gt;. Go ahead and remove or comment out the remotes in the &lt;code&gt;webpack.config.js&lt;/code&gt; file. Another benefit of dynamic remote loading is that we no longer need to declare the modules to help TypeScript. Feel free to delete the &lt;code&gt;projects/shell/decl.d.ts&lt;/code&gt; file. 🪄&lt;/p&gt;

&lt;p&gt;Double-check everything still works by running &lt;code&gt;npm run run:all&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then stop serving the project and try running only the &lt;code&gt;shell&lt;/code&gt; application by running the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng serve shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You should now see the shell application and only see a console error when navigating to a route served by a micro-frontend remote. Success!&lt;/p&gt;
&lt;h2&gt;
  
  
  Deploy your micro-frontend project using Vercel
&lt;/h2&gt;

&lt;p&gt;Now that the cupcakes site is working locally let's deploy this beautiful website using &lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;. Ensure you've authorized Vercel access to GitHub because we'll take advantage of the built-in integration to deploy changes from the &lt;code&gt;main&lt;/code&gt; branch automatically.&lt;/p&gt;

&lt;p&gt;First, &lt;a href="https://docs.github.com/en/get-started/quickstart/create-a-repo" rel="noopener noreferrer"&gt;push your project up to a GitHub repo&lt;/a&gt;. If you wish to obscure your Okta configuration, you can make the repo private. The Okta configuration code is not confidential information, as single-page applications are public clients. If you don't like committing the configuration values into code, you can load the configuration values at runtime or use environment variables as part of your build step. I won't get into the details of how to handle that here, but I will include some links at the end. Make sure to leave the checkbox for &lt;strong&gt;Initialize this repository with a README&lt;/strong&gt; unchecked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ftpjaxyenpc0pz7qzf7c5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ftpjaxyenpc0pz7qzf7c5.jpg" alt="GitHub repo creation with private repo selected and 'Add a README file' checkbox unchecked" width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Vercel dashboard, press the &lt;strong&gt;+ New Project&lt;/strong&gt; button to import a Git repository. Depending on what permissions you granted to Vercel, you might see your newly created GitHub repo immediately. If not, follow the instructions to adjust GitHub app permissions and allow Vercel access to the repo. Press the &lt;strong&gt;Import&lt;/strong&gt; button for the repo to continue. You'll see a form to configure the project within Vercel.&lt;/p&gt;

&lt;p&gt;The idea behind micro frontends is to be able to deploy each application independently. We can do this in Vercel by creating a separate project for each application. Vercel limits the number of projects for a single repo to three in the free plan. What an extraordinary coincidence!&lt;/p&gt;

&lt;p&gt;First, we'll configure the project for the micro-frontend host, the &lt;code&gt;shell&lt;/code&gt; application. To keep the projects organized, incorporate the application name into the Vercel project name, such as &lt;code&gt;okta-angular-mfe-shell&lt;/code&gt;. You'll also need to update the build command and output directory for the &lt;code&gt;shell&lt;/code&gt; application. Update your configuration to look like the screenshot below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fjvh46vvx7u56i6rmiqb3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fjvh46vvx7u56i6rmiqb3.jpg" alt="Vercel configuration for shell application. The build command is set to 'ng build shell' and the output directory is 'dist/shell/'" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Press the &lt;strong&gt;Deploy&lt;/strong&gt; button to kick off a build and deploy the application.&lt;/p&gt;

&lt;p&gt;You'll see a screenshot of the application and a button to return to the dashboard when finished. On the dashboard, you'll see the deployed URI for the application and a screenshot of the cupcakes storefront. If you visit the URI, the routes won't work yet if you try navigating to the remotes. We need to deploy the remote projects and update the URI to the remotes in the route definition. Keep that URI for the &lt;code&gt;shell&lt;/code&gt; application handy; we'll use it soon.&lt;/p&gt;

&lt;p&gt;Return to the Vercel dashboard, create a new project, and select the same repo to import. This time we'll configure the remote application &lt;code&gt;mfe-basket&lt;/code&gt;. Update your configuration to look like the screenshot below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fdix5a8sam3ccd98nigh5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdix5a8sam3ccd98nigh5.jpg" alt="Vercel configuration for mfe-basket application. The build command is set to 'ng build mfe-basket' and the output directory is 'dist/mfe-basket/'" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of the deployed URI for the &lt;code&gt;mfe-basket&lt;/code&gt; application.&lt;/p&gt;

&lt;p&gt;Return to the Vercel dashboard to repeat the process for the final remote application, &lt;code&gt;mfe-profile&lt;/code&gt;. Update your configuration to look like the screenshot below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F5m0yu9bp8nbz1bse0dd4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F5m0yu9bp8nbz1bse0dd4.jpg" alt="Vercel configuration for mfe-profile application. The build command is set to 'ng build mfe-profile' and the output directory is 'dist/mfe-profile/'" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of the deployed URI for the &lt;code&gt;mfe-profile&lt;/code&gt; application.&lt;/p&gt;
&lt;h2&gt;
  
  
  Update the routes to support micro-frontend paths for production
&lt;/h2&gt;

&lt;p&gt;We need to update the route definition to include the URI for the deployed application. Now that you have the URI for the two micro-frontend remotes, you can edit &lt;code&gt;projects/shell/app/app-routing.module.ts&lt;/code&gt;. The values in the &lt;code&gt;remoteEntry&lt;/code&gt; configuration option in the &lt;code&gt;loadRemoteModule()&lt;/code&gt; method are where you'd define the path. But if we update this value to use the deployed URI, then you'll no longer be able to run the application remotely.&lt;/p&gt;

&lt;p&gt;We'll use the &lt;code&gt;environments&lt;/code&gt; configuration built into Angular to support both local and deployed environments and define a configuration for serving locally versus production build.&lt;/p&gt;

&lt;p&gt;We'll configure serving locally first. Open &lt;code&gt;projects/shell/src/environments/environment.ts&lt;/code&gt; and add a new property for the micro-frontend remotes.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;mfe&lt;/span&gt;&lt;span class="p"&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;mfeBasket&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;http://localhost:4201&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;mfeProfile&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;http://localhost:4202&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;Next, we'll use the values in the route definition. Open &lt;code&gt;projects/shell/src/app/app-routing.module.ts&lt;/code&gt; and update the &lt;code&gt;remoteEntry&lt;/code&gt; properties to use the new properties in the &lt;code&gt;environment.ts&lt;/code&gt; file below.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;environment&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="s1"&gt;../environments/environment&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;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProductsComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;basket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadChildren&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="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;remoteEntry&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;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mfe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mfeBasket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/remoteEntry.js`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;exposedModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BasketModule&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadChildren&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="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;remoteEntry&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;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mfe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mfeProfile&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/remoteEntry.js`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;exposedModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ProfileModule&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OktaCallbackComponent&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;Feel free to serve the project using &lt;code&gt;npm run run:all&lt;/code&gt; to double-check everything still works.&lt;/p&gt;

&lt;p&gt;Now we'll add the configuration for the deployed applications. Open &lt;code&gt;projects/shell/src/environments/environment.prod.ts&lt;/code&gt; and add the same property for the micro-frontend remotes. Replace the URI with the deployed location.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;production&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;mfe&lt;/span&gt;&lt;span class="p"&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;mfeBasket&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;https://{yourVercelDeployPath}.vercel.app&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;mfeProfile&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;https://{yourVercelDeployPath}.vercel.app&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;Angular automatically replaces the &lt;code&gt;environment.ts&lt;/code&gt; file to match when you build the project. So if you're serving locally, you'll use the contents from &lt;code&gt;environment.ts&lt;/code&gt;, and if you run &lt;code&gt;ng build&lt;/code&gt; to create the release, you'll use the contents from &lt;code&gt;environment.prod.ts&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;em&gt;Vercel has a release promotion mechanism where you first release to a staging environment to conduct release verification, then promote the verified application to prod. With this flow, we'd need to add more complexity to the way we access the URIs. This tutorial will simplify things to only use one environment, but if you need to handle a multi-step release environment configuration, check out the links to blog posts at the end for handling per-environment configuration.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Add your deployment URL to Okta
&lt;/h3&gt;

&lt;p&gt;You'll need to update the Okta application with the new deploy location so that you can sign in. Open the Okta dashboard. Navigate to &lt;strong&gt;Applications&lt;/strong&gt; &amp;gt; &lt;strong&gt;Applications&lt;/strong&gt; and select the Okta application you created for this project. On the &lt;strong&gt;General&lt;/strong&gt; tab, press the &lt;strong&gt;Edit&lt;/strong&gt; button on the &lt;strong&gt;General Settings&lt;/strong&gt; section and add the new deploy URI for the &lt;code&gt;shell&lt;/code&gt; application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fe6wedzsy1o4wd0jyhjsk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fe6wedzsy1o4wd0jyhjsk.jpg" alt="Okta configuration for adding the Vercel deploy URI of shell application as 'Sign-in redirect URIs' and 'Sign-out redirect URIs'. The 'Sign-in redirect URI' should include the '/login/callback' route, while the 'Sign-out redirect URIs' is the deploy URI as is." width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, add the deploy URI as a Trusted Origin in Okta. Navigate to &lt;strong&gt;Security&lt;/strong&gt; &amp;gt; &lt;strong&gt;API&lt;/strong&gt; and then navigate to the &lt;strong&gt;Trusted Origins&lt;/strong&gt; tab. Press &lt;strong&gt;+ Add Origin&lt;/strong&gt;. Add the deploy location and select &lt;strong&gt;CORS&lt;/strong&gt; for the type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fx7vwouo9n84axsqlmdkq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fx7vwouo9n84axsqlmdkq.jpg" alt="Okta configuration for adding the Vercel deploy URI of shell application to trusted origin. Type 'CORS' is selected." width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Commit your changes and push to your main branch. After the build succeeds, you should be able to use the deployed site from end to end!&lt;/p&gt;
&lt;h2&gt;
  
  
  Secure your micro frontends
&lt;/h2&gt;

&lt;p&gt;Right now, you can access what should be protected routes by manually typing in the full URI to the profile route. Even though you don't see any profile information, we aren't guarding the route. Let's make the site a little more secure by protecting the route.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;projects/shell/src/app/app-routing.module.ts&lt;/code&gt;. We'll add a route guard that comes out of the box with Okta's Angular SDK. Update the route definition for the &lt;code&gt;profile&lt;/code&gt; route as shown below.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;OktaCallbackComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OktaAuthGuard&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="s1"&gt;@okta/okta-angular&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;loadChildren&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="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;remoteEntry&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;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mfe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mfeProfile&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/remoteEntry.js`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;exposedModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ProfileModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;OktaAuthGuard&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;Now if you navigate directly to the profile route, you'll first redirect to Okta's sign-in page, then redirect back to the profile route. &lt;/p&gt;

&lt;p&gt;Route protection works well from within the micro-frontend shell. But what if you navigate directly to the URI where the profile micro frontend resides? You will still be able to navigate to the profile route within the micro frontend because there isn't a guard within the profile application. &lt;/p&gt;

&lt;p&gt;This brings us to an interesting concept. In order to fully secure your micro frontends, you should protect routes defined within your micro frontend as well. To add the Okta route guard, you'll need to import the &lt;code&gt;OktaAuthModule&lt;/code&gt; into the &lt;code&gt;mfe-profile&lt;/code&gt; application's &lt;code&gt;AppModule&lt;/code&gt;, and add the same configuration as you did for the &lt;code&gt;shell&lt;/code&gt; application. The Module Federation configuration shares the Okta library between the applications when accessed via the host application. In contrast, &lt;code&gt;mfe-profile&lt;/code&gt; will need its own instance of authenticated state when accessed in isolation from the &lt;code&gt;shell&lt;/code&gt; application. Having its own instance of authenticated state means you should add sign-in and sign-out capability in the &lt;code&gt;AppComponent&lt;/code&gt; of the &lt;code&gt;mfe-profile&lt;/code&gt; application too. This will also allow you to test each micro-frontend application independently.&lt;/p&gt;

&lt;p&gt;Security + testing = winning!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fniexog7xooaqwzzkb82f.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fniexog7xooaqwzzkb82f.gif" alt="Giphy of man flying with hashtag #winning" width="480" height="288"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Build the micro frontend on a relevant change
&lt;/h2&gt;

&lt;p&gt;As mentioned in this post, the value of micro frontends is the ability to deploy each application independently. In production systems, you may need to handle multiple build steps and build out an entire workflow of CI/CD, but for this tutorial, we can cheat a little and still get the benefits of separate deployments. We will add a configuration in Vercel only to kick off a build when there's changes in the relevant application code.&lt;/p&gt;

&lt;p&gt;From the Vercel dashboard, open the Vercel project for the &lt;code&gt;mfe-basket&lt;/code&gt; application. Navigate to the &lt;strong&gt;Settings&lt;/strong&gt; tab and select &lt;strong&gt;Git&lt;/strong&gt;. In the &lt;strong&gt;Ignored Build Step&lt;/strong&gt;, we can add a Git command to ignore all changes except those in the &lt;code&gt;projects/mfe-basket&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Add the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--quiet&lt;/span&gt; HEAD^ HEAD ./projects/mfe-basket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next, open the Vercel project for the &lt;code&gt;mfe-profile&lt;/code&gt; application to update the &lt;strong&gt;Ignored Build Step&lt;/strong&gt; command. Now add this command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--quiet&lt;/span&gt; HEAD^ HEAD ./projects/mfe-profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Lastly, open the Vercel project for the &lt;code&gt;shell&lt;/code&gt; application to update the &lt;strong&gt;Ignored Build Step&lt;/strong&gt; command. This command is a little different because we want to pick up any changes to the project excluding this changes to &lt;code&gt;mfe-basket&lt;/code&gt; and &lt;code&gt;mfe-profile&lt;/code&gt;. Add the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--quiet&lt;/span&gt; HEAD^ HEAD &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s1"&gt;':!projects/mfe-basket'&lt;/span&gt; &lt;span class="s1"&gt;':!projects/mfe-profile'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, if you make a change in a micro-frontend application, only that micro-frontend application will build and deploy. All three projects will notice the change and start building but will immediately cancel the build if the build step should be ignored for the project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Beyond this post
&lt;/h2&gt;

&lt;p&gt;I hope you've enjoyed creating and deploying this micro-frontend e-commerce site with beautiful pictures of tasty cupcakes. In this post, we used dynamic module loading to load micro frontends lazily within the host application, deployed the project to Vercel, added in multi-environment route configuration, and leveraged a micro-frontend benefit by enabling deployment upon relevant changes. You can check out the completed code for this project in the &lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example/tree/deploy" rel="noopener noreferrer"&gt;&lt;code&gt;deploy&lt;/code&gt; branch of the code repo&lt;/a&gt; by using the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--branch&lt;/span&gt; deploy https://github.com/oktadev/okta-angular-microfrontend-example.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/oktadev" rel="noopener noreferrer"&gt;
        oktadev
      &lt;/a&gt; / &lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example" rel="noopener noreferrer"&gt;
        okta-angular-microfrontend-example
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Starter code + completed project for micro-frontends using Webpack 5 and Module Federation plugin in Angular and sharing authenticated state
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Angular Micro Frontend Example&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This repository shows you how to set up micro frontends using Webpack 5 and Module Federation plugin in Angular and share authenticated state across the project. Please read &lt;a href="https://developer.okta.com/blog/2022/05/17/angular-microfrontend-auth" rel="nofollow noopener noreferrer"&gt;How to Build Micro Frontends Using Module Federation in Angular&lt;/a&gt; to see how it was created.&lt;/p&gt;

&lt;p&gt;This repo accompanies the posts for the Angular micro-frontend series. The starter project is in the &lt;code&gt;main&lt;/code&gt; branch. The completed code for the first post is in the &lt;code&gt;local&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node 16&lt;/li&gt;
&lt;li&gt;Okta CLI&lt;/li&gt;
&lt;li&gt;Angular CLI&lt;/li&gt;
&lt;li&gt;GitHub account&lt;/li&gt;
&lt;li&gt;Vercel account&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://developer.okta.com/" rel="nofollow noopener noreferrer"&gt;Okta&lt;/a&gt; has Authentication and User Management APIs that reduce development time with instant-on, scalable user infrastructure. Okta's intuitive API and expert support make it easy for developers to authenticate, manage and secure users and roles in any application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example#getting-started" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example#links" rel="noopener noreferrer"&gt;Links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example#help" rel="noopener noreferrer"&gt;Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;To run this example, run the following commands:&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/oktadev/okta-angular-microfrontend-example.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; okta-angular-microfrontend-example
npm ci&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Create&lt;/h3&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/oktadev/okta-angular-microfrontend-example" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Learn about Angular, microservices, OpenIDConnect, managing multiple deployment environments, and more
&lt;/h2&gt;

&lt;p&gt;Want to learn more? If you liked this post, check out the following.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/02/24/angular-async-config" rel="noopener noreferrer"&gt;Three Ways to Configure Modules in Your Angular App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/02/22/manage-dotnet-microservices" rel="noopener noreferrer"&gt;Managing Multiple .NET Microservices with API Federation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/04/13/react-azure-functions" rel="noopener noreferrer"&gt;How to Build and Deploy a Serverless React App on Azure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2021/12/08/angular-dynamic-loading" rel="noopener noreferrer"&gt;Loading Components Dynamically in an Angular App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/2022/02/11/angular-auth0-quickly" rel="noopener noreferrer"&gt;Add OpenID Connect to Angular Apps Quickly&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and subscribe to our &lt;a href="https://www.youtube.com/c/OktaDev/" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for more exciting content. We also want to hear from you about what tutorials you want to see. Leave us a comment below.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>tutorial</category>
      <category>microfrontends</category>
      <category>vercel</category>
    </item>
    <item>
      <title>How to Build Micro Frontends Using Module Federation in Angular</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Tue, 24 May 2022 15:05:38 +0000</pubDate>
      <link>https://forem.com/oktadev/how-to-build-micro-frontends-using-module-federation-in-angular-4ib2</link>
      <guid>https://forem.com/oktadev/how-to-build-micro-frontends-using-module-federation-in-angular-4ib2</guid>
      <description>&lt;p&gt;The demands placed on front-end web applications continue to grow.  As consumers, we expect our web applications to be feature-rich and highly performant. As developers, we worry about how to provide quality features and performance while keeping good development practices and architecture in mind.&lt;/p&gt;

&lt;p&gt;Enter micro-frontend architecture. Micro frontends are modeled after the same concept as microservices, as a way to decompose monolithic frontends. You can combine micro-sized frontends  to form a fully-featured web app. Since each micro frontend can be developed and deployed independently, you have a powerful way of scaling out frontend applications.&lt;/p&gt;

&lt;p&gt;So what does the micro-frontend architecture look like? Let's say you have an e-commerce site that looks as stunning as this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fxi3azuizfppzzjfzw55w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fxi3azuizfppzzjfzw55w.jpg" alt="Image of an example e-commerce site selling balloons with a header, links to account &amp;amp; cart, and images of balloons to purchase" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might have a shopping cart, account information for registered users, past orders, payment options, etc. You might be able to further categorize these features into domains, each of which could be a separate micro frontend, also known as a &lt;code&gt;remote&lt;/code&gt;. The collection of micro-frontend remotes is housed inside another website, the &lt;code&gt;host&lt;/code&gt; of the web application.&lt;/p&gt;

&lt;p&gt;So, your e-commerce site using micro frontends to decompose different functionality might look like this diagram, where the shopping cart and account features are in their separate routes within your Single Page Application (SPA):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fb2abqk50jbjvs4hih4y3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fb2abqk50jbjvs4hih4y3.jpg" alt="Image of the example balloon e-commerce site showing a breakdown of the views. The entire site is wrapped in a host named 'Shell', and micro-frontends for the 'Cart' and 'Account' links" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might be saying, "Micro frontends sound cool, but managing the different frontends and orchestrating state across the micro frontends also sounds complicated." You're right. The concept of a micro frontend has been around for a few years and rolling your own micro-frontend implementation, shared state, and tools to support it &lt;em&gt;was&lt;/em&gt; quite an undertaking. However, micro frontends are now well supported with Webpack 5 and &lt;a href="https://webpack.js.org/concepts/module-federation/" rel="noopener noreferrer"&gt;Module Federation&lt;/a&gt;. Not all web apps require a micro-frontend architecture, but for those large, feature-rich web apps that have started to get unwieldy, the first-class support of micro frontends in our web tooling is definitely a plus.&lt;/p&gt;

&lt;p&gt;This post is part one in a series where we'll build an e-commerce site using Angular and micro frontends. We'll use Webpack 5 with Module Federation to support wiring the micro frontends together. Then we'll demonstrate sharing authenticated state between the different frontends, and deploy it all to a free cloud hosting provider. &lt;/p&gt;

&lt;p&gt;In this first post, we'll explore a starter project and understand how the different apps connect, add authentication using Okta, and add the wiring for sharing authenticated state. In the end, you'll have an app that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fjjbr19jed1jgqrnlsxep.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fjjbr19jed1jgqrnlsxep.gif" alt="Animated gif showing the final project with micro-frontends that handle the cupcake shopping basket, authentication, and profile information" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node&lt;/a&gt; This project was developed using Node v16.14 with npm v8.5 &lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular.io/cli" rel="noopener noreferrer"&gt;Angular CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.okta.com" rel="noopener noreferrer"&gt;Okta CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Micro-frontend starter using Webpack 5 and Module Federation
&lt;/h2&gt;

&lt;p&gt;There's a lot in this web app! We'll use a starter code to make sure we focus on the code that's specific to the micro frontend. If you're dismayed that you're using a starter and not starting from scratch, don't worry. I'll provide the Angular CLI commands to recreate the structure of this starter app on the repository's README.md so you have all the instructions.&lt;/p&gt;

&lt;p&gt;Clone the &lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example" rel="noopener noreferrer"&gt;Angular Micro Frontend Example&lt;/a&gt; GitHub repo by following the steps below and open the repo in your favorite IDE.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/oktadev" rel="noopener noreferrer"&gt;
        oktadev
      &lt;/a&gt; / &lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example" rel="noopener noreferrer"&gt;
        okta-angular-microfrontend-example
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Starter code + completed project for micro-frontends using Webpack 5 and Module Federation plugin in Angular and sharing authenticated state
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Angular Micro Frontend Example&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This repository shows you how to set up micro frontends using Webpack 5 and Module Federation plugin in Angular and share authenticated state across the project. Please read &lt;a href="https://developer.okta.com/blog/2022/05/17/angular-microfrontend-auth" rel="nofollow noopener noreferrer"&gt;How to Build Micro Frontends Using Module Federation in Angular&lt;/a&gt; to see how it was created.&lt;/p&gt;
&lt;p&gt;This repo accompanies the posts for the Angular micro-frontend series. The starter project is in the &lt;code&gt;main&lt;/code&gt; branch. The completed code for the first post is in the &lt;code&gt;local&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node 16&lt;/li&gt;
&lt;li&gt;Okta CLI&lt;/li&gt;
&lt;li&gt;Angular CLI&lt;/li&gt;
&lt;li&gt;GitHub account&lt;/li&gt;
&lt;li&gt;Vercel account&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://developer.okta.com/" rel="nofollow noopener noreferrer"&gt;Okta&lt;/a&gt; has Authentication and User Management APIs that reduce development time with instant-on, scalable user infrastructure. Okta's intuitive API and expert support make it easy for developers to authenticate, manage and secure users and roles in any application.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example#getting-started" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example#links" rel="noopener noreferrer"&gt;Links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example#help" rel="noopener noreferrer"&gt;Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;To run this example, run the following commands:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/oktadev/okta-angular-microfrontend-example.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; okta-angular-microfrontend-example
npm ci&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Create&lt;/h3&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/oktadev/okta-angular-microfrontend-example" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/oktadev/okta-angular-microfrontend-example.git
&lt;span class="nb"&gt;cd &lt;/span&gt;okta-angular-microfrontend-example
npm ci
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's dive into the code! 🎉&lt;/p&gt;

&lt;p&gt;We have an Angular project with two applications and one library inside the &lt;code&gt;src/projects&lt;/code&gt; directory. The two applications are named &lt;code&gt;shell&lt;/code&gt; and &lt;code&gt;mfe-basket&lt;/code&gt;, and the library is named &lt;code&gt;shared&lt;/code&gt;. The &lt;code&gt;shell&lt;/code&gt; application is the micro-frontend host, and the &lt;code&gt;mfe-basket&lt;/code&gt; is a micro-frontend remote application. The &lt;code&gt;shared&lt;/code&gt; library contains code and application state we want to share across the site. When you apply the same sort of diagram shown above for this app, it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fpomtk1qh2e6demdys0gx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fpomtk1qh2e6demdys0gx.jpg" alt="Image of the sample cupcake e-commerce site showing a breakdown of the views. The entire site is wrapped in a host named 'shell' and a micro frontend for the 'basket' link" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this project, we use the &lt;code&gt;@angular-architects/module-federation&lt;/code&gt; dependency to help encapsulate some of the intricacies of configuring Webpack and the Module Federation plugin. The &lt;code&gt;shell&lt;/code&gt; and &lt;code&gt;mfe-basket&lt;/code&gt; application have their own separate &lt;code&gt;webpack.config.js&lt;/code&gt;. Open the &lt;code&gt;projects/shell/webpack.config.js&lt;/code&gt; file for either the &lt;code&gt;shell&lt;/code&gt; or &lt;code&gt;mfe-basket&lt;/code&gt; application to see the overall structure. This file is where we add in the wiring for the hosts, remotes, shared code, and shared dependencies in the Module Federation plugin. The structure will be different if you aren't using the &lt;code&gt;@angular-architects/module-federation&lt;/code&gt; dependency, but the basic idea for configuration remains the same.&lt;/p&gt;

&lt;p&gt;Let's explore the sections of this config 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="c1"&gt;// ...imports here&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sharedMappings&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;mf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SharedMappings&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;sharedMappings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../tsconfig.json&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@shared&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...other very important config properties&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&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;ModuleFederationPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;library&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;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;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;

      &lt;span class="c1"&gt;// For remotes (please adjust)&lt;/span&gt;
      &lt;span class="c1"&gt;// name: "shell",&lt;/span&gt;
      &lt;span class="c1"&gt;// filename: "remoteEntry.js",&lt;/span&gt;
      &lt;span class="c1"&gt;// exposes: {&lt;/span&gt;
      &lt;span class="c1"&gt;//     './Component': './projects/shell/src/app/app.component.ts',&lt;/span&gt;
      &lt;span class="c1"&gt;// },        &lt;/span&gt;

      &lt;span class="c1"&gt;// For hosts (please adjust)&lt;/span&gt;
      &lt;span class="na"&gt;remotes&lt;/span&gt;&lt;span class="p"&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;mfeBasket&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;http://localhost:4201/remoteEntry.js&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="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;share&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="c1"&gt;// ...important external libraries to share&lt;/span&gt;

        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sharedMappings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDescriptors&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="nx"&gt;sharedMappings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPlugin&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;In the &lt;code&gt;webpack.config.js&lt;/code&gt; for &lt;code&gt;mfe-basket&lt;/code&gt;, you'll see the path for &lt;code&gt;@shared&lt;/code&gt; at the top of the file and the configuration to identify what to expose in the remote application.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;shell&lt;/code&gt; application serves on port 4200, and the &lt;code&gt;mfe-basket&lt;/code&gt; application serves on port 4201. We can open up two terminals to run each application, or we can use the following npm script created for us by the schematic to add &lt;code&gt;@angular-architects/module-federation&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;npm run run:all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you do so, you'll see both applications open in your browser and how they fit together in the &lt;code&gt;shell&lt;/code&gt; application running on port 4200. Click the &lt;strong&gt;Basket&lt;/strong&gt; button to navigate to a new route that displays the &lt;code&gt;BasketModule&lt;/code&gt; in the &lt;code&gt;mfe-basket&lt;/code&gt; application. The sign-in button doesn't work quite yet, but we'll get it going here next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; - &lt;em&gt;Another option I could have used for the starter is a &lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;Nx workspace&lt;/a&gt;. Nx has great tooling and built-in support for building micro frontends with Webpack and Module Federation. But I wanted to go minimalistic on the project tooling so you'd have a chance to dip your toes into some of the configuration requirements.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@shared&lt;/code&gt; syntax might look a little unusual to you. You may have expected to see a relative path to the library. The &lt;code&gt;@shared&lt;/code&gt; syntax is an alias for the library's path, which is defined in the project's &lt;code&gt;tsconfig.json&lt;/code&gt; file. You don't have to do this. You can leave libraries using the relative path, but adding aliases makes your code look cleaner and helps ensure best practices for code architecture.&lt;/p&gt;

&lt;p&gt;Because the host application doesn't know about the remote applications except in the &lt;code&gt;webpack.config.js&lt;/code&gt;, we help out the TypeScript compiler by declaring the remote application in &lt;code&gt;decl.d.ts&lt;/code&gt;. You can see all the configuration changes and source code made for the starter &lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example/commit/b851320ca9418b8e28890fab15c7da5313eb8275" rel="noopener noreferrer"&gt;in this commit&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add authentication using OpenID Connect
&lt;/h2&gt;

&lt;p&gt;One of the most useful features of Module Federation is managing shared code and state. Let's see how this all works by adding authentication to the project. We'll use the authenticated state in the existing application and with a new micro frontend. &lt;/p&gt;

&lt;p&gt;Before you begin, you’ll need a free Okta developer account. Install the &lt;a href="https://cli.okta.com/" rel="noopener noreferrer"&gt;Okta CLI&lt;/a&gt; and run &lt;code&gt;okta register&lt;/code&gt; to sign up for a new account. If you already have an account, run &lt;code&gt;okta login&lt;/code&gt;. Then, run &lt;code&gt;okta apps create&lt;/code&gt;. Select the default app name, or change it as you see fit. Choose &lt;strong&gt;Single-Page App&lt;/strong&gt; and press &lt;strong&gt;Enter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Use &lt;a href="http://localhost:4200/login/callback" rel="noopener noreferrer"&gt;http://localhost:4200/login/callback&lt;/a&gt; for the Redirect URI and set the Logout Redirect URI to &lt;a href="http://localhost:4200" rel="noopener noreferrer"&gt;http://localhost:4200&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
  What does the Okta CLI do?
  &lt;br&gt;
The Okta CLI will create an OIDC Single-Page App in your Okta Org. It will add the redirect URIs you specified and grant access to the Everyone group. It will also add a trusted origin for &lt;code&gt;http://localhost:4200&lt;/code&gt;. You will see output like the following when it’s finished:&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Okta application configuration:
Issuer:    https://dev-133337.okta.com/oauth2/default
Client ID: 0oab8eb55Kb9jdMIr5d6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: You can also use the Okta Admin Console to create your app. See &lt;a href="https://developer.okta.com/docs/guides/sign-into-spa/angular/create-okta-application/" rel="noopener noreferrer"&gt;Create an Angular App&lt;/a&gt; for more information.&lt;br&gt;
&lt;/p&gt;

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

&lt;p&gt;Make a note of the &lt;code&gt;Issuer&lt;/code&gt; and the &lt;code&gt;Client ID&lt;/code&gt;. You'll need those values here soon.&lt;/p&gt;

&lt;p&gt;We'll use the &lt;a href="https://www.npmjs.com/package/@okta/okta-angular" rel="noopener noreferrer"&gt;Okta Angular&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/@okta/okta-auth-js" rel="noopener noreferrer"&gt;Okta Auth JS&lt;/a&gt; libraries to connect our Angular application with Okta authentication. Add them to your project by running the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @okta/okta-angular@5.2 @okta/okta-auth-js@6.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to import the &lt;code&gt;OktaAuthModule&lt;/code&gt; into the &lt;code&gt;AppModule&lt;/code&gt; of the &lt;code&gt;shell&lt;/code&gt; project and add the Okta configuration. Replace the placeholders in the code below with the &lt;code&gt;Issuer&lt;/code&gt; and &lt;code&gt;Client ID&lt;/code&gt; from earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;OKTA_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OktaAuthModule&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="s1"&gt;@okta/okta-angular&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;OktaAuth&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="s1"&gt;@okta/okta-auth-js&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;oktaAuth&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;OktaAuth&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://{yourOktaDomain}/oauth2/default&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="s1"&gt;{yourClientID}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&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="s1"&gt;/login/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;scopes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openid&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="s1"&gt;profile&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="s1"&gt;email&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;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&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="p"&gt;...,&lt;/span&gt;
    &lt;span class="nx"&gt;OktaAuthModule&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;OKTA_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;oktaAuth&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;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After authenticating with Okta, we need to set up the login callback to finalize the sign-in process. Open &lt;code&gt;app-routing.module.ts&lt;/code&gt; in the &lt;code&gt;shell&lt;/code&gt; project and update the routes array as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;OktaCallbackComponent&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="s1"&gt;@okta/okta-angular&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;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProductsComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;basket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfeBasket/Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BasketModule&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OktaCallbackComponent&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;Now that we've configured Okta in the application, we can add the code to sign in and sign out. Open &lt;code&gt;app.component.ts&lt;/code&gt; in the &lt;code&gt;shell&lt;/code&gt; project. We will add the methods to sign in and sign out using the Okta libraries. We'll also update the two public variables to use the actual authenticated state. Update your code to match the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Inject&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="s1"&gt;@angular/core&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;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shareReplay&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="s1"&gt;rxjs&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;OKTA_AUTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OktaAuthStateService&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="s1"&gt;@okta/okta-angular&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;OktaAuth&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="s1"&gt;@okta/okta-auth-js&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styles&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;isAuthenticated$&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;&amp;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;oktaStateService&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;authState&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authState&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;isAuthenticated&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nf"&gt;shareReplay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;name$&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="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;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;oktaStateService&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;authState&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;authState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authState&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;idToken&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;oktaStateService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OktaAuthStateService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OKTA_AUTH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OktaAuth&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;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&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;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;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signInWithRedirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&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;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;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signOut&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 need to add the click handlers for the sign-in and sign-out buttons. Open &lt;code&gt;app.component.html&lt;/code&gt; in the &lt;code&gt;shell&lt;/code&gt; project. Update the code for &lt;strong&gt;Sign In&lt;/strong&gt; and &lt;strong&gt;Sign Out&lt;/strong&gt; buttons as shown.&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;li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"(isAuthenticated$ | async) === false; else logout"&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center transition ease-in delay-150 duration-300 h-10 px-4 rounded-lg hover:border hover:border-sky-400"&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;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"material-icons-outlined text-gray-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;login&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;nbsp;&lt;/span&gt;Sign In&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#logout&lt;/span&gt;&lt;span class="nt"&gt;&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;"flex items-center transition ease-in delay-150 duration-300 h-10 px-4 rounded-lg hover:border hover:border-sky-400"&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;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"material-icons-outlined text-gray-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;logout&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;nbsp;&lt;/span&gt;Sign Out&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ng-template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try running the project using &lt;code&gt;npm run run:all&lt;/code&gt;. Now you'll be able to sign in and sign out. And when you sign in, a new button for &lt;strong&gt;Profile&lt;/strong&gt; shows up. Nothing happens when you click it, but we're going to create a new remote, connect it to the host, and share the authenticated state here next!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new Angular application
&lt;/h2&gt;

&lt;p&gt;Now you'll have a chance to see how a micro-frontend remote connects to the host by creating a micro-frontend app that shows the authenticated user's profile information. Stop serving the project and run the following command in the terminal to create a new Angular application in the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate application mfe-profile &lt;span class="nt"&gt;--routing&lt;/span&gt; &lt;span class="nt"&gt;--style&lt;/span&gt; css &lt;span class="nt"&gt;--inline-style&lt;/span&gt; &lt;span class="nt"&gt;--skip-tests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this Angular CLI command you&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generated a new application named &lt;code&gt;mfe-profile&lt;/code&gt;, which includes a module and a component&lt;/li&gt;
&lt;li&gt;Added a separate routing module to the application&lt;/li&gt;
&lt;li&gt;Defined the CSS styles to be inline in the components&lt;/li&gt;
&lt;li&gt;Skipped creating associated test files for the initial component&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You'll now create a component for the default route, &lt;code&gt;HomeComponent&lt;/code&gt;, and a module to house the micro frontend. We could wire up the micro frontend to only use a component instead of a module. In fact, a component will cover our needs for a profile view, but we'll use a module so you can see how each micro frontend can grow as the project evolves. Run the following two commands in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate component home &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-profile
ng generate module profile &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-profile &lt;span class="nt"&gt;--module&lt;/span&gt; app &lt;span class="nt"&gt;--routing&lt;/span&gt; &lt;span class="nt"&gt;--route&lt;/span&gt; profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these two Angular CLI commands you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Created a new component, &lt;code&gt;HomeComponent&lt;/code&gt;, in the &lt;code&gt;mfe-profile&lt;/code&gt; application&lt;/li&gt;
&lt;li&gt;Created a new module, &lt;code&gt;ProfileModule&lt;/code&gt;, with routing and a default component, &lt;code&gt;ProfileComponent&lt;/code&gt;. You also added the &lt;code&gt;ProfileModule&lt;/code&gt; as a lazy-loaded route using the '/profile' path to the &lt;code&gt;AppModule&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's update the code. First, we'll add the default route. Open &lt;code&gt;projects/mfe-profile/src/app/app-routing.module.ts&lt;/code&gt; and add a new route for &lt;code&gt;HomeComponent&lt;/code&gt;. Your route array should match the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HomeComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./profile/profile.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ProfileModule&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;Next, we'll update the &lt;code&gt;AppComponent&lt;/code&gt; and &lt;code&gt;HomeComponent&lt;/code&gt; templates. Open &lt;code&gt;projects/mfe-profile/src/app/app.component.html&lt;/code&gt; and delete all the code in there. Replace it with the following:&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;h1&amp;gt;&lt;/span&gt;Hey there! You're viewing the Profile MFE project! 🎉&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;projects/mfe-profile/src/app/home/home.component.html&lt;/code&gt; and replace all the code in the file with:&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;p&amp;gt;&lt;/span&gt;
  There's nothing to see here. 👀 &lt;span class="nt"&gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
  The MFE is this way ➡️ &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/profile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Profile&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we can update the code for the profile. Luckily, Angular CLI took care of a lot of the scaffolding for us. So we just need to update the component's TypeScript file and the template.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;projects/mfe-profile/src/app/profile/profile.component.ts&lt;/code&gt; and edit the component to add the two public properties and include the &lt;code&gt;OktaAuthStateService&lt;/code&gt; in the constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnInit&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="s1"&gt;@angular/core&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;OktaAuthStateService&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="s1"&gt;@okta/okta-angular&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;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&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="s1"&gt;rxjs&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./profile.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styles&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProfileComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;profile$&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;oktaStateService&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;idToken&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;date$&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;oktaStateService&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;idToken&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth_time&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;epochTime&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;epochTime&lt;/span&gt;&lt;span class="p"&gt;)),&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="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;oktaStateService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OktaAuthStateService&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;Next, open the corresponding template file and replace the existing code with the following:&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;h3&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-xl mb-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Your Profile&lt;span class="nt"&gt;&amp;lt;/h3&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;"profile$ | async as profile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Name: &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-semibold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{profile.name}}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"my-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email: &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-semibold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{profile.email}}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Last signed in at &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"font-semibold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{date$ | async | date:'full'}}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;/p&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;Try running the &lt;code&gt;mfe-profile&lt;/code&gt; app by itself by running &lt;code&gt;ng serve mfe-profile --open&lt;/code&gt; in the terminal. Notice when we navigate to the &lt;code&gt;/profile&lt;/code&gt; route, we see a console error. We added Okta into the &lt;code&gt;shell&lt;/code&gt; application, but now we need to turn the &lt;code&gt;mfe-profile&lt;/code&gt; application into a micro frontend and share the authenticated state. Stop serving the application so we're ready for the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Module Federation for your Angular application
&lt;/h2&gt;

&lt;p&gt;We want to use the schematic from &lt;code&gt;@angular-architects/module-federation&lt;/code&gt; to turn the &lt;code&gt;mfe-profile&lt;/code&gt; application into a micro frontend and add the necessary configuration. We'll use port 4202 for this application. Add the schematic by running the following command in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular-architects/module-federation &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-profile &lt;span class="nt"&gt;--port&lt;/span&gt; 4202
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This schematic does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Updates the project's &lt;code&gt;angular.json&lt;/code&gt; config file to add the port for the application and updates the builder to use a custom Webpack builder&lt;/li&gt;
&lt;li&gt;Creates the &lt;code&gt;webpack.config.js&lt;/code&gt; files and scaffolds out default configuration for Module Federation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First, let's add the new micro frontend to the &lt;code&gt;shell&lt;/code&gt; application by updating the configuration in &lt;code&gt;projects/mfe-profile/webpack.config.js&lt;/code&gt;. In the middle of the file, there's a property for &lt;code&gt;plugins&lt;/code&gt; with commented-out code. We need to finish configuring that. Since this application is a remote, we'll update the snippet of code under the comment:&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="c1"&gt;// For remotes (please adjust)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The defaults are mostly correct, except we have a module, not a component that we want to expose. If you want to expose a component instead, all you'd do is update which component to expose. Update the configuration snippet to expose the &lt;code&gt;ProfileModule&lt;/code&gt; by matching the following code snippet:&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="c1"&gt;// For remotes (please adjust)&lt;/span&gt;
&lt;span class="nx"&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;mfeProfile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remoteEntry.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Module&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="s1"&gt;./projects/mfe-profile/src/app/profile/profile.module.ts&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;Now we can incorporate the micro frontend in the &lt;code&gt;shell&lt;/code&gt; application. Open &lt;code&gt;projects/shell/webpack.config.js&lt;/code&gt;. Here is where you'll add the new micro frontend so that the &lt;code&gt;shell&lt;/code&gt; application knows how to access it. In the middle of the file, inside the &lt;code&gt;plugins&lt;/code&gt; array, there's a property for &lt;code&gt;remotes&lt;/code&gt;. The micro frontend in the starter code, &lt;code&gt;mfeBasket&lt;/code&gt;, is already added to the &lt;code&gt;remotes&lt;/code&gt; object. You'll also add the remote for &lt;code&gt;mfeProfile&lt;/code&gt; there, following the same pattern but replacing the port to 4202. Update your configuration to look like this.&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="c1"&gt;// For hosts (please adjust)&lt;/span&gt;
&lt;span class="nx"&gt;remotes&lt;/span&gt;&lt;span class="p"&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;mfeBasket&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;http://localhost:4201/remoteEntry.js&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;mfeProfile&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;http://localhost:4202/remoteEntry.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;p&gt;We can update the code to incorporate the profile's micro frontend. Open &lt;code&gt;projects/shell/src/app/app-routing.module.ts&lt;/code&gt;. Add a path to the profile micro frontend in the routes array using the path 'profile'. Your routes array should look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProductsComponent&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;basket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfeBasket/Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BasketModule&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;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loadChildren&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;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfeProfile/Module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ProfileModule&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OktaCallbackComponent&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;What's this!? The IDE flags the import path as an error! The &lt;code&gt;shell&lt;/code&gt; application code doesn't know about the Profile module, and TypeScript needs a little help. Open &lt;code&gt;projects/shell/src/decl.d.ts&lt;/code&gt; and add the following line of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfeProfile/Module&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;The IDE should be happier now. 😀&lt;/p&gt;

&lt;p&gt;Next, update the navigation button for &lt;strong&gt;Profile&lt;/strong&gt; in the &lt;code&gt;shell&lt;/code&gt; application to route to the correct path. Open &lt;code&gt;projects/shell/src/app/app.component.html&lt;/code&gt; and find the &lt;code&gt;routerLink&lt;/code&gt; for the &lt;strong&gt;Profile&lt;/strong&gt; button. It should be approximately on line 38. Currently the &lt;code&gt;routerLink&lt;/code&gt; configuration is &lt;code&gt;routerLink="/"&lt;/code&gt;, but it should now be&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;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/profile"&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;This is everything we need to do to connect the micro-frontend remote to the host application, but we also want to share authenticated state. Module Federation makes sharing state a piece of (cup)cake.&lt;/p&gt;

&lt;h2&gt;
  
  
  Micro-frontend state management
&lt;/h2&gt;

&lt;p&gt;To share a library, you need to configure the library in the &lt;code&gt;webpack.config.js&lt;/code&gt;. Let's start with &lt;code&gt;shell&lt;/code&gt;. Open &lt;code&gt;projects/shell/src/webpack.config.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are two places to add shared code. One place is for code implementation within the project, and one is for shared external libraries. In this case, we can share the Okta external libraries as we didn't implement a service that wraps Okta's auth libraries, but I will point out both places.&lt;/p&gt;

&lt;p&gt;First, we'll add the Okta libraries. Scroll down towards the bottom of the file to the &lt;code&gt;shared&lt;/code&gt; property. You'll follow the same pattern as the &lt;code&gt;@angular&lt;/code&gt; libraries already in the list and add the singleton instances of the two Okta libraries as shown in this snippet:&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="nx"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;share&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// other Angular libraries remain in the config. This is just a snippet&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/router&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="na"&gt;singleton&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;strictVersion&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;requiredVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&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;@okta/okta-angular&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="na"&gt;singleton&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;strictVersion&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;requiredVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&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;@okta/okta-auth-js&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="na"&gt;singleton&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;strictVersion&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;requiredVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&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="nx"&gt;sharedMappings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDescriptors&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;When you create a library within this project, like the basket service and project service in the starter code, you add the library to the &lt;code&gt;sharedMappings&lt;/code&gt; array at the top of the &lt;code&gt;webpack.config.js&lt;/code&gt; file. If you create a new library to wrap Okta's libraries, this is where you'd add it.&lt;/p&gt;

&lt;p&gt;Now that you've added the Okta libraries to the micro-frontend host, you need to also add them to the remotes that consume the dependencies. In our case, only the &lt;code&gt;mfe-profile&lt;/code&gt; application uses Okta authenticated state information. Open &lt;code&gt;projects/mfe-profile/webpack.config.js&lt;/code&gt;. Add the two Okta libraries to the &lt;code&gt;shared&lt;/code&gt; property as you did for the &lt;code&gt;shell&lt;/code&gt; application.&lt;/p&gt;

&lt;p&gt;Now, you should be able to run the project using &lt;code&gt;npm run run:all&lt;/code&gt;, and the cupcake storefront should allow you to log in, see your profile, log out, and add items to your cupcake basket!&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this first post on creating an Angular micro-frontend site. We explored the capabilities of micro frontends and shared state between micro frontends using Webpack's Module Federation in Angular.  You can check out the completed code for this post in the &lt;a href="https://github.com/oktadev/okta-angular-microfrontend-example/tree/local" rel="noopener noreferrer"&gt;&lt;code&gt;local&lt;/code&gt; branch in the @oktadev/okta-angular-microfrontend-example GitHub repo&lt;/a&gt; by using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--branch&lt;/span&gt; &lt;span class="nb"&gt;local &lt;/span&gt;https://github.com/oktadev/okta-angular-microfrontend-example.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stay tuned for part two. I'll show how to prepare for deployment by transitioning to dynamic module loading and deploying the site to a free cloud provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn about Angular, OpenID Connect, micro frontends, and more
&lt;/h2&gt;

&lt;p&gt;Can't wait to learn more? If you liked this post, check out the following.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/02/24/angular-async-config" rel="noopener noreferrer"&gt;Three Ways to Configure Modules in Your Angular App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2022/02/11/angular-auth0-quickly" rel="noopener noreferrer"&gt;Add OpenID Connect to Angular Apps Quickly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2021/12/08/angular-dynamic-loading" rel="noopener noreferrer"&gt;Loading Components Dynamically in an Angular App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2019/08/08/micro-frontends-for-microservices" rel="noopener noreferrer"&gt;How to Win at UI Development in the World of Microservices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/blog/micro-frontends-with-angular-module-federation-and-auth0/" rel="noopener noreferrer"&gt;Micro Frontends with Angular, Module Federation, and Auth0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and subscribe to our &lt;a href="https://www.youtube.com/c/OktaDev/" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for more exciting content. We also want to hear from you about what tutorials you want to see. Leave us a comment below.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Animating Your Angular App</title>
      <dc:creator>Alisa</dc:creator>
      <pubDate>Tue, 05 Apr 2022 18:14:53 +0000</pubDate>
      <link>https://forem.com/alisaduncan/animating-your-angular-app-598m</link>
      <guid>https://forem.com/alisaduncan/animating-your-angular-app-598m</guid>
      <description>&lt;p&gt;Angular has built-in support for adding animations. In this talk, you'll learn how to add some sparkle to your Angular app by harnessing the power of Angular’s animation library. We’ll start from the basics of state and triggers, use built-in fancy effects, add routing animations, and cover how to make your animations reusable and scalable in this hands-on walk-through. &lt;/p&gt;

&lt;p&gt;This video is ideal for those who have some basic CSS and Angular knowledge. The animations we'll add are straightforward so that we can focus on the capabilities of the Angular animation library. &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/dVp9Ezuv2KU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Animation code
&lt;/h2&gt;

&lt;p&gt;You can check out the starting code for the app. &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/alisaduncan" rel="noopener noreferrer"&gt;
        alisaduncan
      &lt;/a&gt; / &lt;a href="https://github.com/alisaduncan/angular-hero-animations" rel="noopener noreferrer"&gt;
        angular-hero-animations
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Sample app and code for animating the Heroes contact list app for a talk on Angular Animations
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;You can see the finished app with animations in the &lt;code&gt;animations&lt;/code&gt; branch of the repo.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This presentation was prepared for &lt;a href="https://frontdevstage.com/" rel="noopener noreferrer"&gt;Front Stage&lt;/a&gt;. Unfortunately, the conference was canceled due to the ongoing conflicts in Ukraine, where the conference organization is based. 🇺🇦 This talk was also presented at &lt;a href="https://gdg.community.dev/events/details/google-gdg-san-jose-presents-international-womens-day-2022-1/" rel="noopener noreferrer"&gt;International Women's Day San Jose&lt;/a&gt; and &lt;a href="https://www.meetup.com/angularkc/" rel="noopener noreferrer"&gt;AngularKC Meetup&lt;/a&gt; in March 2022.&lt;/em&gt; &lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>angular</category>
      <category>animations</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
