<?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: Afraz Khan</title>
    <description>The latest articles on Forem by Afraz Khan (@afrazkhan).</description>
    <link>https://forem.com/afrazkhan</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%2F495971%2F7d1feffc-3a8a-46a4-b8c7-baa2ebccc572.jpg</url>
      <title>Forem: Afraz Khan</title>
      <link>https://forem.com/afrazkhan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/afrazkhan"/>
    <language>en</language>
    <item>
      <title>How to setup Corporate Identity Access at scale in AWS?</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Fri, 13 Jun 2025 16:16:41 +0000</pubDate>
      <link>https://forem.com/afrazkhan/how-to-setup-corporate-identity-access-at-scale-in-aws-3jol</link>
      <guid>https://forem.com/afrazkhan/how-to-setup-corporate-identity-access-at-scale-in-aws-3jol</guid>
      <description>&lt;p&gt;Imagine a large enterprise with thousands of employees spread across multiple cross-functional teams. Managing access to AWS applications in such an environment can quickly become tedious—especially if you're relying solely on IAM users, IAM roles, and IAM policies to provision access.&lt;/p&gt;

&lt;p&gt;These traditional IAM resources come with inherent limitations, such as role count restrictions, policy size limits, and the impracticality of managing access on a per-user basis. This manual process not only consumes time but also becomes increasingly unsustainable as the organization scales.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html" rel="noopener noreferrer"&gt;AWS IAM Identity Center&lt;/a&gt; (formerly AWS SSO) comes in. It simplifies access management by allowing administrators to integrate their existing identity provider (such as Microsoft Entra ID, Okta, or Cognito Userpool) and automatically synchronize users and groups. This enables access provisioning at scale while reducing the overhead of manual configuration.&lt;/p&gt;

&lt;p&gt;More details on automatic provisioning can be found in the &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/provision-automatically.html" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can also create and manage users directly within IAM Identity Center, if you don’t have an external identity provider.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Federate Access to Your Applications
&lt;/h2&gt;

&lt;p&gt;Once your user directory is set up in IAM Identity Center, you can grant application access to users directly from the console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/manage-your-applications.html" rel="noopener noreferrer"&gt;Application Access&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are two types of applications that can be integrated:&lt;/p&gt;

&lt;h4&gt;
  
  
  AWS-Managed Applications
&lt;/h4&gt;

&lt;p&gt;These applications are native to AWS and are maintained by AWS itself. They provide access to AWS services and features, and administrators configure access through the relevant AWS service consoles. They apply access rules in there as well. Multiple AWS services support this integration natively.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;More detailes &amp;gt; &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/awsapps.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Custom Applications
&lt;/h4&gt;

&lt;p&gt;These are third-party or in-house applications that are either hosted on AWS or outside of it but need to access AWS resources on behalf of users.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;More details &amp;gt; &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/customermanagedapps.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Trusted Identity Propagation
&lt;/h2&gt;

&lt;p&gt;Trusted Identity Propagation is a feature of IAM Identity Center that enables your custom applications to access AWS resources with fine-grained, user-based access control.&lt;/p&gt;

&lt;p&gt;These AWS resources are typically part of AWS-managed applications, and Trusted Identity Propagation allows custom applications to securely interact with them on behalf of a user.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;More details &amp;gt; &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/trustedidentitypropagation-overview.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  S3 Access Grants Use Case
&lt;/h3&gt;

&lt;p&gt;Trusted Identity Propagation is supported across several AWS services, but for this blog, we’ll walk through setting it up using S3 Access Grants.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Supported usecase &amp;gt; &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/trustedidentitypropagation-integrations.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this scenario, S3 Access Grants acts as the AWS-managed application, while we simulate a custom application that uses an Amazon Cognito User Pool as both the identity provider (IdP) and OAuth 2.0 authorization server.&lt;/p&gt;

&lt;p&gt;This setup demonstrates how TIP enables your application to make fine-grained, user-context-aware access requests to Amazon S3 securely and at scale.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Caution: TIP only works with OAuth 2.0 applications&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Setup Guide
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Import the IdP into IAM Identity Center&lt;/p&gt;

&lt;p&gt;You can also create users manually in IAM Identity Center.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: User attribute mapping is important. Ensure that &lt;br&gt;
attribute values match across both systems-for example, &lt;br&gt;
&lt;code&gt;username(Cognito) == username(Identity Center)&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;See example of IAM Identity Center user in below figure.&lt;/em&gt;&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%2Fkncbsngwijckfafk3wv3.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%2Fkncbsngwijckfafk3wv3.png" alt="Image description" width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set Trust Relationship with the OAuth 2.0 Server&lt;/p&gt;

&lt;p&gt;Set up your custom application's OAuth 2.0 authorization server as a &lt;strong&gt;Trusted Token Issuer&lt;/strong&gt;.&lt;br&gt;
Follow the guide &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/using-apps-with-trusted-token-issuer.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I did set up a Cognito Userpool for that purpose.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create custom application in Identity Center&lt;/p&gt;

&lt;p&gt;Register your custom app in IAM Identity Center and attach the previously defined Trusted Token Issuer.&lt;br&gt;
Follow the guide &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/customermanagedapps-trusted-identity-propagation-set-up-your-own-app-OAuth2.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set up Trusted Identity Propagation&lt;/p&gt;

&lt;p&gt;Configure which AWS-managed applications (like S3 Access Grants) your custom application can access, and specify the users or groups that are authorized.&lt;br&gt;
Learn more &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/trustedidentitypropagation-using-customermanagedapps-specify-trusted-apps.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Custom application is grnated access to S3 Access grants (AWS-managed application) in below figure.&lt;/em&gt;&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%2Fbh6zig04x5arhbk0jllt.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%2Fbh6zig04x5arhbk0jllt.png" alt="Image description" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set up S3 Access Grants&lt;/p&gt;

&lt;p&gt;Now, configure the S3 Access Grant for a desired S3 location. This enables an AWS-managed application for S3 Access Grants.&lt;br&gt;
Follow the guide &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-grants-get-started.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;S3 Access Grant sample&lt;/em&gt;&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%2Fy6vam43h4xjcwya8sp67.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%2Fy6vam43h4xjcwya8sp67.png" alt="Image description" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, the setup is complete, let’s move on to the execution part.&lt;/p&gt;

&lt;p&gt;Before diving in, it’s important to understand the concept of Identity-Enhanced IAM Role Sessions, which is a key prerequisite for Trusted Identity Propagation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Identity Enhanced IAM Role Sessions
&lt;/h3&gt;

&lt;p&gt;Whenever a custom application needs to access an AWS service or resource, it follows these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Fetch an Identity Token:&lt;br&gt;
The application contacts IAM Identity Center to exchange its JWT(IdToken) for a new JWT(IdToken) via the &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/API_CreateTokenWithIAM.html" rel="noopener noreferrer"&gt;CreateTokenWithIAM&lt;/a&gt; API. This token contains the identity context of the currently signed-in user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Assume an IAM Role:&lt;br&gt;
The application then assumes an IAM role using the &lt;a href="https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html" rel="noopener noreferrer"&gt;AssumeRole&lt;/a&gt; API. It attaches the identity context along with the request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access AWS Resources:&lt;br&gt;
Using the returned temporary AWS credentials, the application accesses the AWS resource (e.g., S3 via Access Grants).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Audit and Monitoring via CloudTrail:&lt;br&gt;
The associated AWS service (like S3) logs the user identity context in CloudTrail.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Example below&lt;/em&gt;&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%2Fjnscqoovoy19z3vvtmgr.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%2Fjnscqoovoy19z3vvtmgr.png" alt="Image description" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This enables auditing, monitoring, and debugging based on the actual user's identity, not just the application's role.&lt;/p&gt;

&lt;p&gt;The diagram below illustrates this flow clearly:&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%2Fs26thj4bpy24ggh6rd0f.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%2Fs26thj4bpy24ggh6rd0f.png" alt="Image description" width="685" height="661"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Trusted Identity Propagation(TIP) IN Action
&lt;/h3&gt;

&lt;p&gt;As the custom application accesses AWS resources using Identity-Enhanced IAM role credentials, the target AWS service intercepts each request and validates access based on the attached user identity context.&lt;/p&gt;

&lt;p&gt;In our case, S3 Access Grants evaluates the request against the authorization rules defined and either ALLOWS or DENIES access accordingly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;See &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_GetDataAccess.html" rel="noopener noreferrer"&gt;GetDataAccess&lt;/a&gt; API&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the core of Trusted Identity Propagation—ensuring that access control decisions are made based on the original user's identity, not just the permissions of the application role.&lt;/p&gt;

&lt;p&gt;The diagram below illustrates the complete design:&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%2F14z0mzx4xa6qqjmp7oz5.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%2F14z0mzx4xa6qqjmp7oz5.png" alt="Image description" width="741" height="661"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Sample Notebook
&lt;/h3&gt;

&lt;p&gt;I’ve implemented the flow in a Jupyter notebook, which you can find &lt;a href="https://github.com/afraz-khan/aws/blob/main/AWS-IAM-Identity-Center/Trusted-Identity-Propagation-Sample.ipynb" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;. Feel free to fork it and set it up for your own experimentation.&lt;/p&gt;

&lt;p&gt;If you encounter any issues during the setup, refer to the official documentation &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-grants-directory-ids.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;That’s all for now. I hope this blog helps you implement scalable access for your AWS applications. Happy learning! 😊&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>iam</category>
      <category>cloudcomputing</category>
    </item>
    <item>
      <title>Implementing Single Sign-On (SSO) in Your Microsoft Teams Bot App [Part II]</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Sun, 08 Sep 2024 20:39:41 +0000</pubDate>
      <link>https://forem.com/afrazkhan/implementing-single-sign-on-sso-in-your-microsoft-teams-bot-app-part-2-3k7d</link>
      <guid>https://forem.com/afrazkhan/implementing-single-sign-on-sso-in-your-microsoft-teams-bot-app-part-2-3k7d</guid>
      <description>&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. &lt;a href="https://dev.to/afrazkhan/building-a-microsoft-teams-bot-app-step-by-step-setup-guide-part-1-ndh"&gt;Part I - Simple Teams Bot App Setup&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. &lt;strong&gt;Part II - Enable SSO for Teams Bot App&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In the previous article, we explored the process of setting up a simple echo bot app in Teams. In this article, we will examine the Single Sign-On (SSO) options for enabling authentication in a Teams bot app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teams Bot App SSO
&lt;/h2&gt;

&lt;p&gt;Teams apps are available in the Teams client either through the app store or via Admin-approved apps section &lt;em&gt;"Build for your org"&lt;/em&gt;. It means users must be logged into Teams before accessing the apps.&lt;/p&gt;

&lt;p&gt;So by default, no additional login is required for users to access the app. However, if you want to enable authentication for your app, SSO is one of the options available. Users will be prompted to consent to the scopes defined by the app. Once consent is given, the user is granted access to the app.&lt;/p&gt;

&lt;p&gt;Technically, a token is generated for each bot message request. This token can be used in the bot backend to make API calls to various Microsoft services (e.g., Skype, OneNote) on behalf of the user.&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%2Fe4m1piwrxmjemumcwl5p.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%2Fe4m1piwrxmjemumcwl5p.png" alt="Bot App SSO" width="800" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more information, &lt;a href="https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/bot-sso-overview" rel="noopener noreferrer"&gt;visit here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s dive into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSO Setup
&lt;/h2&gt;

&lt;p&gt;To configure SSO for your Teams bot app, you need to update three components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Entra ID App&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bot Registration in Azure Bot Service&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minor Updates in the Teams Developer Portal App&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;(We created all these resources in the previous article)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I won’t detail the configuration steps for these components here, as comprehensive guides are available from Microsoft on their official documentation platforms. You can refer to the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-conversation-sso-quickstart/BotSSOSetup.md" rel="noopener noreferrer"&gt;SSO Setup Guide on GitHub Samples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/bot-sso-register-aad?tabs=botid" rel="noopener noreferrer"&gt;SSO Setup Guide on the Official User Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  OAuth Dialog Flow
&lt;/h2&gt;

&lt;p&gt;Once the initial setup is complete, it’s time to implement some code changes. You need to integrate an OAuth dialog flow into your existing bot app, which will enable the Bot Framework to handle the complete SSO authentication flow.&lt;/p&gt;

&lt;p&gt;For each bot message received, this dialog flow is executed. Its responsibility is to fetch the token from the Bot Framework Token Service and make it available in the message context. For more details, please refer to the SSO architecture discussed in the first section of this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  No User Consent
&lt;/h3&gt;

&lt;p&gt;You can implement this OAuth dialog flow according to your use case. If you prefer not to have users provide explicit consent and only want to acquire the token directly, you should enable "Admin Consent" for all the scopes/permissions in the Microsoft Entra ID 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%2F23qtv5qz9yk66rcvtlpi.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%2F23qtv5qz9yk66rcvtlpi.png" alt="Admin Consent" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If there is no Admin Consent then users are shown a consent screen everytime there is request for new token generation from the Bot Framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Changes for a Node.js Bot Backend
&lt;/h3&gt;

&lt;p&gt;To integrate SSO into your existing bot app, you'll need to restructure and add some components to the Bot backend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inject SSO Middleware&lt;/strong&gt;
Integrate the SSO middleware into your bot to handle authentication flow.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;TeamsSSOTokenExchangeMiddleware&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;botbuilder&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;tokenExchangeMiddleware&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;TeamsSSOTokenExchangeMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;memoryStorage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connectionName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokenExchangeMiddleware&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Implement OAuth Dialog&lt;/strong&gt;
I’m pasting the smallest possible version of the dialog code below. Feel free to tweak it as needed.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Copyright (c) Microsoft Corporation. All rights reserved.&lt;/span&gt;
&lt;span class="c1"&gt;// Licensed under the MIT License.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ConfirmPrompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DialogSet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DialogTurnStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OAuthPrompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WaterfallDialog&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;botbuilder-dialogs&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LogoutDialog&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./logoutDialog&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;CONFIRM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ConfirmPrompt&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;MAIN_DIALOG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MainDialog&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;MAIN_WATERFALL_DIALOG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MainWaterfallDialog&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;OAUTH_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OAuthPrompt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainDialog&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;LogoutDialog&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;userState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MAIN_DIALOG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OAuthConnectionName&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;addDialog&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;OAuthPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OAUTH_PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;connectionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OAuthConnectionName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please Sign In&lt;/span&gt;&lt;span class="dl"&gt;'&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;Sign In&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300000&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;addDialog&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;ConfirmPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CONFIRM_PROMPT&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;addDialog&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;WaterfallDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MAIN_WATERFALL_DIALOG&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;promptStep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;processTokenStep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="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;initialDialogId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MAIN_WATERFALL_DIALOG&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;userState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userState&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;authTokenAccessor&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;userState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AuthToken&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="cm"&gt;/**
     * The run method handles the incoming activity (in the form of a DialogContext) and passes it through the dialog system.
     * If no dialog is active, it will start the default dialog.
     * @param {*} dialogContext
     */&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accessor&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;dialogSet&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;DialogSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accessor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;dialogSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dialogContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;dialogSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;dialogContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;continueDialog&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;results&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;DialogTurnStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;dialogContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginDialog&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;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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;promptStep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;OAUTH_PROMPT&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="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;processTokenStep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stepContext&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;tokenResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&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;tokenResponse&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;tokenResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authentication was not successful please try again.&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;else&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;authTokenAccessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tokenResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endDialog&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MainDialog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MainDialog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Attach User State, Conversation State, and OAuth Dialog&lt;/strong&gt;
Configure your bot to use &lt;code&gt;userState&lt;/code&gt;, &lt;code&gt;conversationState&lt;/code&gt;, and the OAuth dialog to manage user interactions and authentication.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;CloudAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;ConversationState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;MemoryStorage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;UserState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;ConfigurationBotFrameworkAuthentication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;TeamsSSOTokenExchangeMiddleware&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;botbuilder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Create conversation and user state with in-memory storage provider.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;conversationState&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;ConversationState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;memoryStorage&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;userState&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;UserState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;memoryStorage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Create the main dialog.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dialog&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;MainDialog&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Create the bot that will handle incoming messages.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bot&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;TeamsBot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conversationState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache the Token&lt;/strong&gt;
Implement logic to save the token for future use. The recommended approach is to persist the token in the Bot user state cache. See the Dialog logic above. For more details on managing cache and state in the bot backend, refer to the &lt;a href="https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/bot-sso-code?tabs=js1%2Cjs2%2Cjs3%2Ccs4%2Ccs5&amp;amp;pivots=bot-app" rel="noopener noreferrer"&gt;official guide&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access the Token in the Bot&lt;/strong&gt;
Once token is saved in the cache via th OAuth Dialog. Make changes in your Bot's &lt;code&gt;onMessage&lt;/code&gt; endpoint to load it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DialogBot&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TeamsActivityHandler&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;conversationState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&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;conversationState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&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;[DialogBot]: Missing parameter. conversationState is required&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;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;userState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&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;[DialogBot]: Missing parameter. userState is required&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;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;dialog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&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;[DialogBot]: Missing parameter. dialog is required&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conversationState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;conversationState&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;userState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userState&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;dialog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dialog&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;dialogState&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;conversationState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DialogState&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;authTokenAccessor&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;userState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AuthToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.&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;onMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OnMessage: New message is received.&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;processingMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Processing your request...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Dialog is executed&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;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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;dialogState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Load the token from the cache&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authToken&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;authTokenAccessor&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="nx"&gt;context&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Token ==&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt; &lt;span class="nx"&gt;authToken&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;memberData&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="nf"&gt;getTeamsMemberInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`OnMessage: member ==&amp;gt; "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt; &lt;span class="nx"&gt;memberData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aadObjectId&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;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateActivity&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;processingMessage&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="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;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thanks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="c1"&gt;// By calling next() you ensure that the next BotHandler is run.&lt;/span&gt;
            &lt;span class="k"&gt;await&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;span class="cm"&gt;/**
    * Override the ActivityHandler.run() method to save state changes after the bot logic completes.
    */&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Save any state changes. The load happened during the execution of the Dialog.&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;conversationState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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="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;userState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getTeamsMemberInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;TeamsInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMember&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;response&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DialogBot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DialogBot&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 are done 😍. Now SSO is enabled for the bot app.&lt;/p&gt;

&lt;p&gt;All of these changes are mentioned on the &lt;a href="https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/bot-sso-code?tabs=cs1%2Ccs2%2Ccs3%2Ccs4%2Ccs5&amp;amp;pivots=bot-app" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; and also refer to the &lt;a href="https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-conversation-sso-quickstart/js" rel="noopener noreferrer"&gt;SSO sample&lt;/a&gt;. Again, You can play around with this sample as per your usecase.&lt;/p&gt;

&lt;p&gt;Happy learning 🚀!!!&lt;/p&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. &lt;a href="https://dev.to/afrazkhan/building-a-microsoft-teams-bot-app-step-by-step-setup-guide-part-1-ndh"&gt;Part I - Simple Teams Bot App Setup&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. &lt;strong&gt;Part II - Enable SSO for Teams Bot App&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>microsoft</category>
      <category>msteams</category>
      <category>azure</category>
      <category>security</category>
    </item>
    <item>
      <title>Building a Microsoft Teams Bot App – Step-by-Step Setup Guide [Part I]</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Sun, 08 Sep 2024 20:29:55 +0000</pubDate>
      <link>https://forem.com/afrazkhan/building-a-microsoft-teams-bot-app-step-by-step-setup-guide-part-1-ndh</link>
      <guid>https://forem.com/afrazkhan/building-a-microsoft-teams-bot-app-step-by-step-setup-guide-part-1-ndh</guid>
      <description>&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. &lt;strong&gt;Part I - Simple Teams Bot App Setup&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. &lt;a href="https://dev.to/afrazkhan/implementing-single-sign-on-sso-in-your-microsoft-teams-bot-app-part-2-3k7d"&gt;Part II - Enable SSO for Teams Bot App&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Microsoft Teams is a powerful collaboration platform, and integrating a bot can streamline numerous tasks for your team. In this guide, I'll walk you through the process of setting up a Bot App in Microsoft Teams, covering everything from app registration to deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Buy subscriptions for MS365 and Azure.&lt;/li&gt;
&lt;li&gt;Ensure you use the same tenant for Microsoft Teams and Azure.&lt;/li&gt;
&lt;li&gt;Install the &lt;a href="https://ngrok.com/" rel="noopener noreferrer"&gt;ngrok&lt;/a&gt; to setup an HTTP tunnel.&lt;/li&gt;
&lt;li&gt;Install Nodejs18.x.&lt;/li&gt;
&lt;li&gt;Follow the steps in the specified order to avoid issues during setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Microsoft Entra ID App Registration
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Register a New Application

&lt;ul&gt;
&lt;li&gt;Go to the &lt;a href="https://go.microsoft.com/fwlink/?linkid=2083908" rel="noopener noreferrer"&gt;Microsoft Entra ID – App Registrations portal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Register a new application. Choose options that suit your use case.
&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%2Fg4ui92p4j8n6050p59d4.png" alt="App Registration" width="800" height="817"&gt;
&lt;/li&gt;
&lt;li&gt;save the Application/Client ID for future use.
&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%2Fmuve1wxlrcb1nlgju778.png" alt="App Registration" width="800" height="149"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Create Client Secret

&lt;ul&gt;
&lt;li&gt;Navigate to "Certificates and Secrets" and create a new client secret.&lt;/li&gt;
&lt;li&gt;Make sure to save the secret value immediately, as it is revealed only once.
&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%2Fek1lgv6xexc61j97ikqx.png" alt="App Registration" width="800" height="386"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 2: Setting up the Bot Backend Service
&lt;/h2&gt;

&lt;p&gt;Teams Bots are developed using the &lt;a href="https://learn.microsoft.com/en-us/microsoftteams/platform/bots/bot-features?tabs=dotnet#bots-with-the-microsoft-bot-framework" rel="noopener noreferrer"&gt;Microsoft Bot Framework&lt;/a&gt;, a collection of tools and SDKs designed to build intelligent bots. To get started, you need to set up the backend service for the bot. &lt;em&gt;(Bot registration is performed in the very next section)&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the Echo Bot Sample

&lt;ul&gt;
&lt;li&gt;Download a simple echo bot &lt;em&gt;(written in nodejs)&lt;/em&gt; from the &lt;a href="https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/javascript_nodejs/02.echo-bot" rel="noopener noreferrer"&gt;sample here&lt;/a&gt;. This bot just responds with the same user message as received.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update Environment Variables&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update the environment variables in the &lt;code&gt;.env&lt;/code&gt; file of the downloaded project:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  MicrosoftAppType={"MultiTenant" or "SingleTenant" based on                         the setting you selected while creating the app registration}
  MicrosoftAppId={App ID from previous step}
  MicrosoftAppPassword={App Password from previous step}
  MicrosoftAppTenantId={ignore if multi-tenant app else put the tenant-id}
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the Backend&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the relevant README file to run the backend.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set Up HTTP Tunnel&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now, set up an HTTP tunnel at port 3978 via ngrok.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 3: Bot Registration in Azure Bot Service
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a Bot Framework Registration Resource&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the &lt;a href="https://portal.azure.com/" rel="noopener noreferrer"&gt;Azure Portal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a Bot Framework registration resource.

&lt;ul&gt;
&lt;li&gt;In the left panel, select Create a resource.&lt;/li&gt;
&lt;li&gt;In the search box enter &lt;em&gt;&lt;strong&gt;bot&lt;/strong&gt;&lt;/em&gt;, then press Enter.&lt;/li&gt;
&lt;li&gt;Select the Azure Bot card.
&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%2F36gv741r7aij75gtm01n.png" alt="Bot Registration" width="568" height="896"&gt; &lt;/li&gt;
&lt;li&gt;Select Create.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Provide the necessary details such as project details, data residency, and app ID from the previous step.
&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%2Fc46ge96h3963gnorcvcl.png" alt="Bot Registration" width="800" height="327"&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%2F2jr7xjjjzt2kb5pl0cys.png" alt="Bot Registration" width="800" height="542"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable the Teams Channel&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure to enable the Teams Channel in the bot settings.
&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%2Fmk1hm0ywnmywo022kora.png" alt="Bot Registration" width="800" height="487"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set Up Messaging Endpoint&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure the messaging endpoint with below Url format:
&lt;code&gt;https://{ngrok-domain}/api/messages&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4: App Registration in Teams Developer Portal
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a New App

&lt;ul&gt;
&lt;li&gt;Sign in to the &lt;a href="https://dev.teams.microsoft.com/home" rel="noopener noreferrer"&gt;Teams Developer Portal&lt;/a&gt; and create a new app.
&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%2F8dgd79gdcfb09oyx0lvo.png" alt="Teams Dev Portal App Registration" width="800" height="158"&gt;
&lt;/li&gt;
&lt;li&gt;Fill in the required fields under the "Basic Information" section, including the MS Entra ID app ID.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Branding and Features

&lt;ul&gt;
&lt;li&gt;Update the app icons under the "Branding" section.&lt;/li&gt;
&lt;li&gt;In "App Features," setup the Bot feature for the app. or link the Bot feature tile with the MS Entra ID app ID.
&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%2Flf6g2axsvzvwsc2u1wj7.png" alt="Teams Dev Portal App Registration" width="800" height="432"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Allow Required Domains&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Navigate to "Domains" and allow the following domains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*.ngrok-free.app&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*.ngrok.io&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;When setting up for production, be sure to allow the production service domain here once you're ready. Additionally, for successfull app auth, you need to allow other domains as well, such as &lt;code&gt;token.botframework.com&lt;/code&gt; is mandatory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 5: App Distribution
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Validate the App&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Teams Developer Portal, navigate to your app.&lt;/li&gt;
&lt;li&gt;Use the App Validation section to check for any critical issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Publish the App&lt;br&gt;
As per your requirements, you can publish the app to the App Store or your organization etc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For organization wide apps, publish the app to your organization via the "Publish to Org" section.&lt;/li&gt;
&lt;li&gt;Request your Teams Admin to approve and distribute the app within the organization.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Installation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once approved, the bot will be available for installation in the Teams client.
&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%2Fkit164460tqy7ab9g6ko.png" alt="Teams App" width="800" height="320"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;You may need to go through a rigorous approval process to publish the app to the store. For more information, refer to the documentation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Sample Bot UI
&lt;/h3&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%2Fe0gcef8gsb4fgdtm8fsl.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%2Fe0gcef8gsb4fgdtm8fsl.png" alt="Teams App" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ref ==&amp;gt; [&lt;a href="https://learn.microsoft.com/en-us/microsoftteams/platform/bots/what-are-bots" rel="noopener noreferrer"&gt;1&lt;/a&gt;], [&lt;a href="https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/apps-publish-overview" rel="noopener noreferrer"&gt;2&lt;/a&gt;]&lt;/p&gt;




&lt;p&gt;Next, we will enable authentication for the app using Microsoft SSO.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. &lt;strong&gt;Part I - Simple Teams Bot App Setup&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. &lt;a href="https://dev.to/afrazkhan/implementing-single-sign-on-sso-in-your-microsoft-teams-bot-app-part-2-3k7d"&gt;Part II - Enable SSO for Teams Bot App&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>microsoft</category>
      <category>msteams</category>
      <category>node</category>
      <category>azure</category>
    </item>
    <item>
      <title>Whitelisting URL Paths Using Regular Expressions</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Sun, 28 Apr 2024 00:27:58 +0000</pubDate>
      <link>https://forem.com/afrazkhan/whitelisting-url-paths-using-regular-expressions-4hb7</link>
      <guid>https://forem.com/afrazkhan/whitelisting-url-paths-using-regular-expressions-4hb7</guid>
      <description>&lt;p&gt;In software development, there are times when you need to restrict the execution of certain blocks of code based on the incoming request URL. One common way to achieve this in a web application is by whitelisting specific URL paths using regular expressions (regex).&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Use Regular Expressions?
&lt;/h3&gt;

&lt;p&gt;By using regex, you can create a pattern that matches a set of URL paths that you want to allow or "whitelist". This approach provides flexibility and allows you to define complex matching criteria for your whitelisted paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Whitelist
&lt;/h3&gt;

&lt;p&gt;To whitelist specific request paths, you'll need to create a regular expression for each path. Once you have all the individual regex patterns, you can merge them into a single regex pattern for better performance.&lt;/p&gt;

&lt;p&gt;Here's an example demonstrating how to create a whitelist using a single regex pattern:&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="cm"&gt;/**
 * Regular expression pattern for whitelisting request paths.
 * Each pattern represents an allowed HTTP method and path.
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;whiteListedPathsPattern&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;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;`^GET /api/user$`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`^POST /api/app//products/search$`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`^POST /api/app/uninstall$`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`^POST /api/app/disconnect$`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`^GET /api/app/complaince/[a-z_]*$`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`^POST /api/notification/brand$`&lt;/span&gt;&lt;span class="p"&gt;,&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="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="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;incomingRequestUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;URL_HERE&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;whiteListedPathsPattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;incomingRequestUrl&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Execute your code block&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request is whitelisted. Proceeding with the execution...&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;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle unauthorized request&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request is not whitelisted. Access denied.&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;h3&gt;
  
  
   Complete Express.js Example
&lt;/h3&gt;

&lt;p&gt;For a comprehensive example demonstrating how to implement this in an Express.js application, check out this &lt;a href="https://gist.github.com/afraz-khan/8666b111d55ffaa8a7d33df12b9e1d94#file-whitelist_request_paths-ts"&gt;GitHub Gist&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>learning</category>
    </item>
    <item>
      <title>Transforming TypeScript Enums into Object Arrays</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Sat, 20 Jan 2024 14:41:03 +0000</pubDate>
      <link>https://forem.com/afrazkhan/transforming-typescript-enums-into-object-arrays-h0j</link>
      <guid>https://forem.com/afrazkhan/transforming-typescript-enums-into-object-arrays-h0j</guid>
      <description>&lt;p&gt;Typescript enums are of three types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Numeric enum:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All enum members have numeric values.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;String enum:&lt;/strong&gt;&lt;br&gt;
All enum members have string values.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Heterogeneous enum:&lt;/strong&gt;&lt;br&gt;
Enum members are mixed but its essential for numeric members to follow a valid numeric value order.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In TypeScript, enums are compiled into JavaScript objects (&lt;a href="https://www.typescriptlang.org/docs/handbook/enums.html#enums-at-runtime"&gt;here&lt;/a&gt;). As a result, native object methods &lt;code&gt;Object.values()&lt;/code&gt; and &lt;code&gt;Object.keys()&lt;/code&gt;can be used at runtime to construct an object array from an enum. However, please note that the process may differ for each enum type.&lt;/p&gt;

&lt;h3&gt;
  
  
  String enum
&lt;/h3&gt;

&lt;p&gt;Its the most straight-forward enum type to constract arrays from. Utilize the &lt;code&gt;Object.values()&lt;/code&gt; or &lt;code&gt;Object.keys()&lt;/code&gt; method, depending on your specific requirements.&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;enum&lt;/span&gt; &lt;span class="nx"&gt;Scope&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;CREATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;UPDATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;DELETE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;delete&lt;/span&gt;&lt;span class="dl"&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;Scopes&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;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ["create", "edit", "delete"]&lt;/span&gt;

&lt;span class="nx"&gt;Scopes&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;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ["CREATE", "UPDATE", "DELETE"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Numeric enum
&lt;/h3&gt;

&lt;p&gt;As enums are compiled to objects, accessing the value of an enum member using its key is standard. However, with numeric enums, the reverse is also possible – you can access the enum member key/name using its value. This behavior is referred to as &lt;strong&gt;&lt;em&gt;Reverse-Mapping&lt;/em&gt;&lt;/strong&gt;. &lt;a href="https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings"&gt;Read more&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In essence, keys become values, and values become keys :). Consequently, the output array of both &lt;code&gt;Object.values()&lt;/code&gt; and &lt;code&gt;Object.keys()&lt;/code&gt; methods will have twice the number of elements compared to the original enum.&lt;/p&gt;

&lt;p&gt;You have the flexibility to trim or transform the results according to your specific requirements. 👇&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="c1"&gt;// Numeric enum starting from 2.&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;Scope&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;CREATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;UPDATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;DELETE&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;Scopes&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;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ["CREATE", "UPDATE", "DELETE", 2, 3, 4] &lt;/span&gt;

&lt;span class="nx"&gt;Scopes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&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;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ["CREATE", "UPDATE", "DELETE"]&lt;/span&gt;

&lt;span class="nx"&gt;Scopes&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;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ["2", "3", "4", "CREATE", "UPDATE", "DELETE"]&lt;/span&gt;

&lt;span class="nx"&gt;Scopes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&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;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ["2", "3", "4"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Heterogeneous enum
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;There is no Reverse-Mapping available for string enums or string enum members in case of Heterogeneous enums.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Output of &lt;code&gt;Object.keys()&lt;/code&gt; and &lt;code&gt;Object.values()&lt;/code&gt; depends on the number of string and numeric members present in the enum.&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="c1"&gt;// Heterogeneous enum with one string and three numeric members&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;Scope&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;CREATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;UPDATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;DELETE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;GET&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;Scopes&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;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ["CREATE", "DELETE", "GET", 0, "edit", 4, 5]&lt;/span&gt;

&lt;span class="nx"&gt;Scopes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Scopes&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;scp&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;scp&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ["CREATE", "DELETE", "GET", "edit"]&lt;/span&gt;

&lt;span class="nx"&gt;Scopes&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;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ["0", "4", "5", "CREATE", "UPDATE", "DELETE", "GET"]&lt;/span&gt;

&lt;span class="nx"&gt;Scopes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Scopes&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;scp&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ["0", "4", "5"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Happy learning!! 💪&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>programming</category>
      <category>node</category>
    </item>
    <item>
      <title>Elevating Code Flexibility: Dependency Inversion with DI Containers</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Mon, 03 Jul 2023 12:05:02 +0000</pubDate>
      <link>https://forem.com/afrazkhan/elevating-code-flexibility-dependency-inversion-with-di-containers-3686</link>
      <guid>https://forem.com/afrazkhan/elevating-code-flexibility-dependency-inversion-with-di-containers-3686</guid>
      <description>&lt;p&gt;Having tight-coupling between classes and objects is consistently detrimental, as it diminishes code flexibility and reusability. Each modification to a single component necessitates the vigorous task of dealing with its dependencies, causing developers to face recurring challenges. &lt;br&gt;
In the realm of software development, the following design patterns serve as fundamental pillars extensively employed to eliminate tight coupling, especially when adhering to the &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;SOLID&lt;/a&gt; principles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Inversion-of-Control (&lt;a href="https://en.wikipedia.org/wiki/Inversion_of_control"&gt;IoC&lt;/a&gt;)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency-Injection (&lt;a href="https://en.wikipedia.org/wiki/Dependency_injection"&gt;DI&lt;/a&gt;)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency-Inversion-Principle (&lt;a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle"&gt;DIP&lt;/a&gt;)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These patterns offer developers the means to decouple dependencies and achieve code that is flexible, maintainable, and extensible.&lt;/p&gt;

&lt;p&gt;Furthermore, the modern landscape of development practices has witnessed the emergence of highly acclaimed &lt;strong&gt;"DI Containers"&lt;/strong&gt; frameworks. These frameworks have revolutionized the implementation of IoC and DI, empowering developers to construct software architectures that are robust, modular, and scalable.&lt;/p&gt;

&lt;p&gt;Lets review a practical example to employ the powerful Dependency Inversion Principle that results in modular and clean design. Examples are written for a TypeScript-based codebase utilizing &lt;a href="https://inversify.io/"&gt;InversifyJS&lt;/a&gt; as the DI Container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preliminary Setup
&lt;/h2&gt;

&lt;p&gt;Lets expect that your application has a DI container set up, with each class appropriately attached to it using the necessary procedures. In InversifyJS, creating an application container is as straightforward as shown below:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;code&gt;AppContainer.ts&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&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;Container&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;inversify&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;ServiceOne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ServiceTwo&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;../services&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;AppContainer&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;static&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Container&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;static&lt;/span&gt; &lt;span class="nf"&gt;build&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;container&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;Container&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ServiceOne&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;ServiceOne&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ServiceOne&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ServiceTwo&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;ServiceTwo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ServiceTwo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Practical Use Case
&lt;/h2&gt;

&lt;p&gt;Lets take a fictional Authentication module in a codebase that solely relies on Google as the Identity Provider for managing authentication. However, a new requirement has emerged to incorporate Amazon as an additional Identity Provider.&lt;/p&gt;

&lt;h4&gt;
  
  
  👇 Current Code Structure
&lt;/h4&gt;

&lt;p&gt;Imagine a service named &lt;code&gt;Authenticator&lt;/code&gt; that primarily relies on Google as the identity provider, exemplified in the code snippet below.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;code&gt;Authenticator.ts&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&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;Authenticator&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;initiateUserAuth&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="c1"&gt;// Google specific operations    &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;logoutUser&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="c1"&gt;// Google specific operations    &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;h4&gt;
  
  
  ⭕ Tight Coupling found
&lt;/h4&gt;

&lt;p&gt;In this scenario, the code exhibits tight coupling as the &lt;code&gt;Authenticator&lt;/code&gt; service directly relies on the Google as the Identity Provider. To accommodate new Identity Providers, the code requires the introduction of if/else statements and as the number of Identity Providers grows, maintaining this code becomes increasingly complex and challenging. Now, it becomes evident that a significant restructuring is necessary to accommodate the integration of a new Identity Provider.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Looks like an exhastive task? 🙂&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  🍯 Desired Objective
&lt;/h4&gt;

&lt;p&gt;The seamless integration of new Identity Providers should be accomplished without requiring any significant or even zero modifications to the &lt;code&gt;Authenticator&lt;/code&gt; service.&lt;/p&gt;

&lt;h4&gt;
  
  
  🔍 Analysis
&lt;/h4&gt;

&lt;p&gt;By leveraging the &lt;strong&gt;Dependency Inversion Principle&lt;/strong&gt;, we can decouple the &lt;code&gt;Authenticator&lt;/code&gt; service from the specific Google implementation. This involves introducing an abstract class or interface as a protocol for all Identity Providers to adhere to. Such decoupling ensures that changes or additions to low-level modules, like Google or Amazon Identity Provider, won't directly affect the high-level &lt;code&gt;Authenticator&lt;/code&gt; module, promoting modularity and maintainability in the codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resolution
&lt;/h3&gt;

&lt;p&gt;We require a substantial yet straightforward restructuring, outlined as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Introduce a new module called IdentityProvider. Within this module, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an interface named &lt;code&gt;IIdentityProvider&lt;/code&gt; that encompasses essential methods and properties universally applicable to all Identity Providers in your system.&lt;/li&gt;
&lt;li&gt;Create an enum &lt;code&gt;EIdentityProvider&lt;/code&gt; for the Identity Provider types.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;code&gt;IIdentityProvider.ts&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&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;IIdentityProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetchTokens&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;revokeTokens&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;export&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;EIdentityProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;GOOGLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GOOGLE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;AMAZON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AMAZON&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;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new &lt;code&gt;GoogleIdentityProvider&lt;/code&gt; class which implements the &lt;code&gt;IIdentityProvider&lt;/code&gt; interface.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;code&gt;GoogleIdentityProvider.ts&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&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;GoogleIdentityProvider&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;IIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetchTokens&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="c1"&gt;// google specific operations&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;revokeTokens&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;// google specific operations&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;/li&gt;
&lt;li&gt;
&lt;p&gt;Similar to &lt;code&gt;GoogleIdentityProvider&lt;/code&gt;, Create a new &lt;code&gt;AmazonIdentityProvider&lt;/code&gt; class. &lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;code&gt;AmazonIdentityProvider.ts&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&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;AmazonIdentityProvider&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;IIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetchTokens&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="c1"&gt;// Amazon specific operations&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;revokeTokens&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;// Amazon specific operations&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;/li&gt;
&lt;li&gt;
&lt;p&gt;Refactor the &lt;code&gt;Authenticator&lt;/code&gt; class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduce a new property called &lt;code&gt;identityProvider&lt;/code&gt;, which stores the relevant Identity Provider instance based on the use case. Utilize this property to carry out the authentication process.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  &lt;em&gt;&lt;strong&gt;&lt;code&gt;Authenticator.ts&lt;/code&gt;&lt;/strong&gt;&lt;/em&gt;
&lt;/h4&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;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;inversify&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;Authenticator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;identityProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IIdentityProvider&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;identityProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IIdentityProvider&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;identityProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;identityProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/* Authentication-related methods that are independent
     of any specific Identity Provider. */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;initiaUserAuth&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identityProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchTokens&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;logoutUser&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identityProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;revokeTokens&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure multiple instances of the &lt;code&gt;Authenticator&lt;/code&gt; class in the DI Container. Each instance is initialized using a specific &lt;code&gt;IdentityProvider&lt;/code&gt; type. To accomplish this, we will leverage the service identification methods offered by your DI Container framework.&lt;/p&gt;

&lt;p&gt;See InversifyJS example below.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;code&gt;AppContainer.ts&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&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;Container&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;inversify&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;Authenticator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GoogleIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AmazonIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;IdentityProvider&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;../services&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;AppContainer&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;static&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Container&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;static&lt;/span&gt; &lt;span class="nf"&gt;build&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;container&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;Container&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="cm"&gt;/* Initialize an instance of each Identity Provider 
       class. */&lt;/span&gt;
    &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GoogleIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GoogleIdentityProvider&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;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GoogleIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AmazonIdentityProvider&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;AmazonIdentityProvider&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;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AmazonIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Initialize multiple Authenticator instances based on 
       each Identity Provider type. */&lt;/span&gt;
    &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Authenticator&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;Authenticator&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;toDynamicValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Authenticator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&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;GoogleIdentityProvider&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;whenTargetTagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;IdentityProvider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Authenticator&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;Authenticator&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;toDynamicValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Authenticator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&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;AmazonIdentityProvider);
      })
      .whenTargetTagged(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;IdentityProvider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, EIdentityProvider.AMAZON);
  }
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Refactor the code, specifically in the sections where you want to load the suitable &lt;code&gt;Authenticator&lt;/code&gt; instance based on the required Identity Provider type in the use case.&lt;/p&gt;

&lt;p&gt;Take a look at the provided InversifyJS examples in a hypothetical Authentication Controller scenario.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;code&gt;AuthController.ts&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&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;AppContainer&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;../AppContainer.ts&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;Authenticator&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../Authenticator.ts&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;AuthController&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;authenticator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Authenticator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/auth/google&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;initiateGoogleAuth&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;

    &lt;span class="c1"&gt;// Loading Authenticator instance with GOOGLE Identity Provider&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;authenticator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AppContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authenticator&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;IdentityProvider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;EIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE&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;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/auth/amazon&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;initiateAmazonAuth&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;

    &lt;span class="c1"&gt;// Loading Authenticator instance with AMAZON Identity Provider&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;authenticator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AppContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTagged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authenticator&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;IdentityProvider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;EIdentityProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AMAZON&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Default Implementation with Decorator Pattern
&lt;/h2&gt;

&lt;p&gt;If 📜default behavior is necessary for your Identity Providers, considering an &lt;strong&gt;abstract class&lt;/strong&gt; instead of an &lt;strong&gt;interface&lt;/strong&gt; is a viable option. Moreover, if that default behavior serves as a valid form of an identity provider, it may be appropriate for the class to be &lt;strong&gt;concrete&lt;/strong&gt;.&lt;br&gt;
Other specific Identity Providers can inherit from this class, allowing them to modify or override the functionality as required. This particular scenario is a great application of the &lt;a href="https://en.wikipedia.org/wiki/Decorator_pattern"&gt;Decorator Pattern&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a component Interface.&lt;/li&gt;
&lt;li&gt;Create a default-identity-provider/component class which implements component interface.&lt;/li&gt;
&lt;li&gt;Create decorator/specific-identity-provider classes that inherit from the component class.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good Decorator Pattern example &lt;a href="https://refactoring.guru/design-patterns/decorator/typescript/example"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;I hope, this helped you:), happy learning🚀&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;refs&lt;/em&gt;&lt;/strong&gt; &lt;a href="https://martinfowler.com/articles/dipInTheWild.html#YouMeanDependencyInversionRight"&gt;1&lt;/a&gt;, &lt;a href="https://coderstower.com/2019/03/26/dependency-inversion-why-you-shouldnt-avoid-it/"&gt;2&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>cleancode</category>
      <category>programming</category>
      <category>coding</category>
    </item>
    <item>
      <title>Reuse Redis Connections across AWS Lambda invocations</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Mon, 24 Apr 2023 13:35:39 +0000</pubDate>
      <link>https://forem.com/afrazkhan/reuse-redis-connecitons-across-aws-lambda-invocations-4kk</link>
      <guid>https://forem.com/afrazkhan/reuse-redis-connecitons-across-aws-lambda-invocations-4kk</guid>
      <description>&lt;p&gt;If you are familiar with the lambda execution environment and how it works for a single lambda function invocation, then it's a great opportunity for you to optimise your application's performance. The lambda execution environment enables you to persist and reuse DB connections, especially in situations where &lt;strong&gt;latency&lt;/strong&gt; must be taken into account and connection open/close at the same time is not desirable.&lt;br&gt;
 👉 &lt;em&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html" rel="noopener noreferrer"&gt;Lambda Execution Environment&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Recently, I have implemented a solution for reusing Redis client connections across the invocations of a lambda function in a single lambda execution environment, I will share that here today. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;small&gt;Note that examples are given using TypeScript and &lt;br&gt;
this blog could even help you to reuse your database connections (MySQL, PostgreSQL, etc.).&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1. Make use of Lambda Static Initialization
&lt;/h3&gt;

&lt;p&gt;The code placed outside of function's main handler method is run only when execution environment is spinned up for the first time. Lambda keeps that code as long as environment is warm.&lt;br&gt;
 👉 &lt;em&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/operatorguide/static-initialization.html" rel="noopener noreferrer"&gt;Static Initialization&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initialize a global variable outside the handler method that saves the Redis client object.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;blockquote&gt;
&lt;p&gt;&lt;small&gt;You can put this global Redis client variable in any file as per your function's code structure. Its not necessary to keep it in the handler method file.&lt;/small&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Setup Idle Connection Timeout in Redis/database
&lt;/h3&gt;

&lt;p&gt;Since, we want to reuse the database connections so, no need to end newly created connections.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hence, delete the connection-close logic from your lambda function. If you have multiple usecases in your lambda function then do it only for those where you want to reuse the existing connection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that, once a lambda execution environemnt is taken down, these opened connections become useless and they can take up as much memory to cause &lt;em&gt;&lt;strong&gt;OUT OF MEMORY&lt;/strong&gt;&lt;/em&gt; errors in Redis/database server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Configure an idle connection timeout in Redis.&lt;em&gt;(or in your database service)&lt;/em&gt; to terminate these idle connections automatically.&lt;/p&gt;

&lt;p&gt;👉 &lt;em&gt;&lt;a href="https://redis.io/docs/reference/clients/#client-timeouts" rel="noopener noreferrer"&gt;Redis Client Handling&lt;/a&gt;&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;You need to be careful here, analyse your application requirements and configure a timeout in Redis as per your need.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;small&gt;It shouldn't be larger than the lambda execution environment idle timeout which lies somewhere between 40-50mins. I found this stat online but there's no proper evidence about it. You may wanna perform tests to find it yourself :)&lt;/small&gt;&lt;/em&gt;&lt;br&gt;
 &lt;em&gt;&lt;small&gt;Also, it shouldn't be very small at the same time, otherwise, your lambda function might create new connections as frequently as it matches the previous rate and this whole effort becomes pointless.&lt;/small&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Update Redis Client Creation Logic
&lt;/h3&gt;

&lt;p&gt;You need to update the client creation logic based on two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If existing client is active and working then function uses that instead of creating a new one.&lt;/li&gt;
&lt;li&gt;Client would be reset if existing connection is terminated by Redis/database engine in the wake of connection idle timeout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are multiple ways to manage it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a separate method called &lt;code&gt;getRedisClient()&lt;/code&gt; as shown in the below figure. Keep the client reuse/reset logic in that method and only use it throughout the lambda function for fetching an active Redis client.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6idhhe23oercjh4t8lid.png" alt="generic-mehtod"&gt;
This approach is cleaner and maintainable. If your application can bear the extra &lt;code&gt;ping()&lt;/code&gt; call, then it is a good solution.&lt;/li&gt;
&lt;li&gt;Here, move the client reset logic into the API methods like below. It saves you the &lt;code&gt;ping()&lt;/code&gt; call, so it is more performant. 
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dzqxbn36wf122gy5kcx.png" alt="api-method"&gt;
This approach is favorable when your lambda function is doing only one task. If you have multiple business logic operations in your function, then maybe not a good option. You will have to insert the client reset logic in all those methods where Redis operations are performed. Not good for clean code principles.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Implement a &lt;strong&gt;Global Error Handler&lt;/strong&gt; in the lambda function or a pattern like that. See if lambda &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-retries.html" rel="noopener noreferrer"&gt;retry&lt;/a&gt; mechanism helps for that. Basiaclly, idea is to transmit all errors to that error handler where the Redis/database client is reset as done in the second approach.&lt;/p&gt;

&lt;p&gt;This looks like a perfect solution that avoids the extra &lt;code&gt;ping()&lt;/code&gt; call in the first approach and the repetition pattern in the second approach.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I chose the first approach as it suited my application. The third option is just an idea that I didn't experiment with cz I am busy with other things🥲. Maybe you can give it a try and let me know :)&lt;/p&gt;




&lt;p&gt;After updating the Redis client creation logic, your lambda funtions are all set🚀 to reuse the existing connections.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>redis</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Cross-Account Deployment with AWS SAM</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Wed, 29 Mar 2023 22:43:34 +0000</pubDate>
      <link>https://forem.com/afrazkhan/cross-account-aws-sam-deployment-1ndf</link>
      <guid>https://forem.com/afrazkhan/cross-account-aws-sam-deployment-1ndf</guid>
      <description>&lt;p&gt;AWS &lt;a href="https://aws.amazon.com/serverless/sam/"&gt;SAM&lt;/a&gt; is a serverless framework that allows you to easily develop and deploy serverless applications in AWS environments.&lt;br&gt;
Today, I will describe a couple of methods to execute cross-account SAM deployments that I have recently come across.&lt;br&gt;
When we talk about multi-account deployment, we typically mean that your team has a central AWS account for devops-related activities, such as all of your CI/CD &lt;em&gt;(Continuous Integration and Continuous Deployment)&lt;/em&gt; pipelines, which are in charge of deploying infrastructure and code changes to each application environment as the pull requests are merged.&lt;/p&gt;
&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;There is a SAM project in your codebase that has some lambda functions to run. Requirement is to deploy this SAM project in the application account &lt;em&gt;(lets call it &lt;strong&gt;Dev-Account&lt;/strong&gt;)&lt;/em&gt; but via the devops account &lt;em&gt;(lets call it &lt;strong&gt;DevOps-Account&lt;/strong&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Resolution
&lt;/h2&gt;

&lt;p&gt;In &lt;em&gt;&lt;strong&gt;Dev-Account&lt;/strong&gt;&lt;/em&gt;, deploy below resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We need to use a &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html"&gt;cross-account&lt;/a&gt; IAM role in the &lt;em&gt;&lt;strong&gt;Dev-Account&lt;/strong&gt;&lt;/em&gt; that will be assumed by &lt;em&gt;&lt;strong&gt;DevOps-Account&lt;/strong&gt;&lt;/em&gt; for carrying out the needed deployment actions.

&lt;ul&gt;
&lt;li&gt;Put all permissions that &lt;em&gt;&lt;strong&gt;DevOps-Account&lt;/strong&gt;&lt;/em&gt; needs to execute the deployment in &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Put the &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt; in the trust-relationship of this role.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(&lt;em&gt;Trust entity would look like below&lt;/em&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Version"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Statement"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Principal"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:iam::{DevOpsAccountID}:root"&lt;/span&gt;
            &lt;span class="pi"&gt;},&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts:AssumeRole"&lt;/span&gt;
        &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt;, deploy below resources: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS &lt;a href="https://aws.amazon.com/codepipeline/"&gt;CodePipeline&lt;/a&gt; pipeline which has at-least 2 stages. Let's call them &lt;strong&gt;Source&lt;/strong&gt; and &lt;strong&gt;Deploy&lt;/strong&gt;. You can add more stages as per your need)
&lt;em&gt;(&lt;a href="https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create.html"&gt;https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create.html&lt;/a&gt;)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;An S3 bucket where CodePipeline stores the artifacts coming from different stages/actions of the pipeline. &lt;em&gt;(You can place this bucket either in &lt;strong&gt;Dev-Account&lt;/strong&gt; or &lt;strong&gt;DevOps-Account&lt;/strong&gt;, just update the policy accordingly)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;A Customer-Managed KMS key in the &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt; that is used by CodePipeline to encrypt/decrypt the objects in the artifacts bucket.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Deploy&lt;/strong&gt; Action in the CodePipeline must invoke a &lt;a href="https://aws.amazon.com/codebuild/"&gt;CodeBuild&lt;/a&gt; project.&lt;em&gt;(read more about it in below section)&lt;/em&gt; This project is essentially responsible to building and deploying our SAM application. &lt;em&gt;(&lt;code&gt;sam build&lt;/code&gt;, &lt;code&gt;sam deploy&lt;/code&gt; commands)&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Each CodeBuild build is supposed to obtain the &lt;code&gt;buildspec&lt;/code&gt; file from the pipeline stage input artifacts.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  CodeBuild Project Location
&lt;/h2&gt;

&lt;p&gt;Now, we need to decide about the location of the CodeBuild project&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Integration tools, such as Codebuild, are typically stored in the devops/operations account alongside pipelines, but they can be moved to your application account as well. This is where the solution design can take several forms, and you must decide which one is best for you. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1. CodeBuild project placed in &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0x7t1j19qodqsiukf997.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0x7t1j19qodqsiukf997.jpg" alt="CodeBuild-in-dev" width="572" height="313"&gt;&lt;/a&gt;&lt;br&gt;
I designed this solution myself, without online assistance like AWS forums or other platforms. Maybe you have already seen things like this, but it works.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spin-up a CodeBuild project in the &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create an IAM service role for CodeBuild in the &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt;. Provide the necessary permissions to this role, like CodePipeline artifacts bucket permissions, &lt;em&gt;&lt;strong&gt;DevOps-Account&lt;/strong&gt;&lt;/em&gt; KMS key permissions, CloudFormation permissions for SAM, and others as required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;(Find sample policy below)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Version"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Statement"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sid"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VisualEditor0"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:Decrypt"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:Encrypt"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:DescribeKey"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:ReEncrypt*"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:GenerateDataKey*"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{DevOpsAccountKMSKeyArn}"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="pi"&gt;},&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sid"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VisualEditor1"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cloudformation:*"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
        &lt;span class="pi"&gt;},&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sid"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VisualEditor2"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:Get*"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:Put*"&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:ListBucket"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{ArtifactsBucketArn}/*"&lt;/span&gt;
        &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure that the artifacts bucket policy and &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt; KMS Key Policy have access permissions for the &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt; CodeBuild service role.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an IAM service role for CodePipeline in &lt;em&gt;&lt;strong&gt;DevOps-Account&lt;/strong&gt;&lt;/em&gt; that has CodePipeline service in the trust-relationship and &lt;code&gt;sts:AssumeRole&lt;/code&gt; permission to assume the cross-account role in &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;It must have permission to invoke the CodeBuild project in the &lt;em&gt;&lt;strong&gt;Dev-Account&lt;/strong&gt;&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;(Find the sample policy below)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Version"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Statement"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts:AssumeRole"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{CrossAccountRoleArn&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;DevAccount}"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sid"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CrossAccountAssumeRolePolicy"&lt;/span&gt;
        &lt;span class="pi"&gt;},&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;codestar-connections:UseConnection"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sid"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AllowCodeStarConnection"&lt;/span&gt;
        &lt;span class="pi"&gt;},&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;codebuild:StartBuild"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;codebuild:BatchGetBuilds"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;codebuild:BatchGetBuildBatches"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;codebuild:StartBuildBatch"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:codebuild:{Region}:{DevAccountId}:project/*"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sid"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CodeBuildPolicy"&lt;/span&gt;
        &lt;span class="pi"&gt;},&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:DescribeKey"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:GetKeyPolicy"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:List*"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:Encrypt"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:Decrypt"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:ReEncrypt*"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:Generate*"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{CustomerManagedKeyArn&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;DevOps&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Account}"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sid"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;KMSPolicy"&lt;/span&gt;
        &lt;span class="pi"&gt;}&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:*"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sid"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S3Policy"&lt;/span&gt;
        &lt;span class="pi"&gt;},&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iam:PassRole"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sid"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PassRolePolicy"&lt;/span&gt;
        &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Assign the &lt;em&gt;&lt;strong&gt;Dev-Account&lt;/strong&gt;&lt;/em&gt; cross-account IAM role to the &lt;strong&gt;Deploy&lt;/strong&gt; stage action of the pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. CodeBuild project placed in &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffp5nndbh9ng3cf30w5hy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffp5nndbh9ng3cf30w5hy.jpg" alt="CodeBuild-in-devops" width="572" height="313"&gt;&lt;/a&gt;&lt;br&gt;
I guess this is the most effective approach, at-least for me :) because I want all my CD/CD resources to be in one place. It makes the management and tracking of resources easier.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create the CodeBuild project in the &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;No need to assign any IAM role to the &lt;strong&gt;Deploy&lt;/strong&gt; stage action in the pipeline because the CodeBuild project is in the &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt; and the action will inherit the CodeBuild permissions from the parent pipeline service role.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Create an IAM service role for CodeBuild in the &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt; that has CodeBuild service in the trust-relationship and &lt;code&gt;sts:AssumeRole&lt;/code&gt; permission to assume the cross-account role in &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Version"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Statement"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="pi"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts:AssumeRole"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{CrossAccountRoleArn&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;DevAccount}"&lt;/span&gt;
            &lt;span class="pi"&gt;],&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Effect"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sid"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CrossAccountAssumeRolePolicy"&lt;/span&gt;
        &lt;span class="pi"&gt;},&lt;/span&gt;
        &lt;span class="nv"&gt;.&lt;/span&gt;
        &lt;span class="nv"&gt;.&lt;/span&gt;
        &lt;span class="nv"&gt;.&lt;/span&gt;
        &lt;span class="nv"&gt;.&lt;/span&gt;
        &lt;span class="nv"&gt;.&lt;/span&gt;

    &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Since, CodeBuild project is in the &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt;, so SAM commands will deploy the resources in the &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt; that is not correct. So, we need to set the &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt; credentials in the CodeBuild project in order for it to deploy the resources into the &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;Use the AWS &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html"&gt;Security-Token-Service&lt;/a&gt; to get the temporary credentials for the &lt;em&gt;&lt;strong&gt;Dev-Account&lt;/strong&gt;&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;(Update your buildspec file like below)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;

&lt;span class="na"&gt;phases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo getting AWS credentials for "$CROSSACCOUNT_SAM_ROLE"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;CREDENTIAL=$(aws sts assume-role \&lt;/span&gt;
          &lt;span class="s"&gt;--duration-seconds 900&lt;/span&gt;
          &lt;span class="s"&gt;--role-arn "$CROSSACCOUNT_SAM_ROLE" \&lt;/span&gt;
          &lt;span class="s"&gt;--role-session-name SAMSession \&lt;/span&gt;
          &lt;span class="s"&gt;--output text \&lt;/span&gt;
          &lt;span class="s"&gt;--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken,Expiration]')&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export AWS_ACCESS_KEY_ID=$(echo $CREDENTIAL | awk '{print $1}')&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIAL | awk '{print $2}')&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export AWS_SESSION_TOKEN=$(echo $CREDENTIAL | awk '{print $3}')&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export SESSION_EXPIRATION=$(echo $CREDENTIAL | awk '{print $4}')&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sam build&lt;/span&gt;      
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sam deploy --no-confirm-changeset --no-fail-on-empty-changeset&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$CROSSACCOUNT_SAM_ROLE&lt;/code&gt; environment variable in above &lt;code&gt;buildspec&lt;/code&gt; file refers to the cross-account &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt; IAM role.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure that, cross-account IAM role has all necessary permissions needed to deploy the SAM resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SAM --role-arn arg
&lt;/h3&gt;

&lt;p&gt;You might think that, there must be a way for the SAM to assume the cross-account IAM role in &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt; instead of generating the credentials explicitly. It would be a more cool🧊 solution, ain't it?&lt;/p&gt;

&lt;p&gt;I tried that myself, there's a parameter in the SAM &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-deploy.html"&gt;deploy&lt;/a&gt; command named --role-arn which basically CloudFormation service assumes to deploy the resources/changes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(My buildspec was simple as below)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;

&lt;span class="na"&gt;phases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sam build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sam deploy --no-confirm-changeset --no-fail-on-empty-changeset --role-arn {CrossAccountDevRoleArn}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This results into below error&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cross-account pass role is not allowed (Service: AmazonCloudFormation; Status Code: 403; Error Code: AccessDenied; Request ID: d880bdd7-fe3f-11e7-8a8c-7dcffeae19ae)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, CodeBuild in &lt;strong&gt;&lt;em&gt;DevOps-Account&lt;/em&gt;&lt;/strong&gt; tries to pass a cross-account IAM role to the CloudFormation service in the &lt;strong&gt;&lt;em&gt;Dev-Account&lt;/em&gt;&lt;/strong&gt; and this is not possible. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You cannot use the &lt;code&gt;PassRole&lt;/code&gt; permission to pass a cross-account role. read &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_passrole.html"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, this hack wouldn't work🙂 and generating the cross-account credentials explicitly is the only solution as per my knowledge or that I could find online.&lt;/p&gt;

&lt;p&gt;happy learning🚀&lt;/p&gt;




&lt;p&gt;ref -&amp;gt; &lt;a href="https://repost.aws/knowledge-center/codepipeline-deploy-cloudformation"&gt;1&lt;/a&gt;, &lt;a href="https://aws.amazon.com/blogs/devops/building-a-ci-cd-pipeline-for-cross-account-deployment-of-an-aws-lambda-api-with-the-serverless-framework/"&gt;2&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create-cross-account.html"&gt;3&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>cicd</category>
      <category>deployments</category>
    </item>
    <item>
      <title>Merge TypeScript Enums</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Sun, 18 Sep 2022 11:33:41 +0000</pubDate>
      <link>https://forem.com/afrazkhan/merge-typescript-enums-4mh7</link>
      <guid>https://forem.com/afrazkhan/merge-typescript-enums-4mh7</guid>
      <description>&lt;p&gt;There is no native support for merging 2 or more enums in typescript but its possible with a combination of &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-aliases"&gt;type aliases&lt;/a&gt; and &lt;a href="https://www.typescriptlang.org/docs/handbook/enums.html#handbook-content"&gt;enums&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge Enums
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Let suppose, you have 2 string based enums:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// enum 1&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;ManagedUserStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;M_STATUS1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;M_STATUS2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;M_STATUS3&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="c1"&gt;// enum 2&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sys_STATUS1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sys_STATUS2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sys_STATUS3&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;ul&gt;
&lt;li&gt;Convert the enums into a single javascript object, lets call it &lt;em&gt;&lt;strong&gt;enum object&lt;/strong&gt;&lt;/em&gt;. Utilize the enum object in your codebase as a regular enum. This object has the union of all enums combined.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// same enum like values&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;UserStatuses&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="nx"&gt;ManagedUserStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// OR&lt;/span&gt;

&lt;span class="c1"&gt;// Kind of nested enum approach&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;UserStatuses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ManagedUserStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a type from the enum object. Use this type as the regular enum type in your codebase.
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Name of this type alias can be same as the enum object or anything else.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. export as an object type&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// OR&lt;/span&gt;

&lt;span class="c1"&gt;// 2. export only the keys&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// OR&lt;/span&gt;

&lt;span class="c1"&gt;// 3. export as a uinon type&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ManagedUserStatus&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, you can merge 2 or more enums and simulate the same enum like behavior in your codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample usage
&lt;/h3&gt;

&lt;p&gt;Lets imagine a method in your code which utilizes our newly created enum.&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;confirmUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserStatus&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;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;M_STATUS2&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Merge Issues
&lt;/h2&gt;

&lt;p&gt;There are some limitations and issues with this kind of merge and you have to be aware of them before merging your enums.&lt;/p&gt;

&lt;h4&gt;
  
  
  Numbered Enums
&lt;/h4&gt;

&lt;p&gt;With numbered enums, you will have duplicate values in the enum object.&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;enum&lt;/span&gt; &lt;span class="nx"&gt;ManagedUserStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 0&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS3&lt;/span&gt;     &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// enum 2&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 0&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS3&lt;/span&gt;   &lt;span class="c1"&gt;// 2&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;UserStatuses&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="nx"&gt;ManagedUserStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure that, if you need unique values then assign proper initializers to your enums like 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="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;ManagedUserStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 0&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS3&lt;/span&gt;     &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// enum 2&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 6&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// 7&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS3&lt;/span&gt;       &lt;span class="c1"&gt;// 8&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Duplicate Keys
&lt;/h4&gt;

&lt;p&gt;If your enums have duplicate keys then that key in the final enum object has over-written value. See below exmple&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;enum&lt;/span&gt; &lt;span class="nx"&gt;ManagedUserStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 0&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS3&lt;/span&gt;     &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// enum 2&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 0&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CONFIRMED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UNCONFIRMED&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;UserStatuses&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="nx"&gt;ManagedUserStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&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;m_status2_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;M_STATUS2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//  'CONFIRMED'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Nested Enums
&lt;/h2&gt;

&lt;p&gt;If you plan to use the nested enums for the enum object then maybe you can ignore above issues because there is no actual merging process in that case. only key based enums are exported out of the enum object. See 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="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;ManagedUserStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 0&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS3&lt;/span&gt;     &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// enum 2&lt;/span&gt;
&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// 0&lt;/span&gt;
  &lt;span class="nx"&gt;M_STATUS2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CONFIRMED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Sys_STATUS3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UNCONFIRMED&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;UserStatuses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ManagedUserStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// no effect of duplicate keys&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mStatus2_one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ManagedUserStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;M_STATUS2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//  '1'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mStatus2_two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;M_STATUS2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//  'CONFIRMED'&lt;/span&gt;

&lt;span class="c1"&gt;// no effect of numbered values&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sysStatus1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserStatuses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SystemUserStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Sys_STATUS1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//  '0'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;happy learning! 👊&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>enum</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>AWS Cognito JWT Verification</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Sat, 19 Feb 2022 23:24:27 +0000</pubDate>
      <link>https://forem.com/afrazkhan/aws-cognito-jwt-verification-5bia</link>
      <guid>https://forem.com/afrazkhan/aws-cognito-jwt-verification-5bia</guid>
      <description>&lt;p&gt;AWS Cognito usually responds with 3 JWTs (&lt;code&gt;IDToken&lt;/code&gt;, &lt;code&gt;AccessToken&lt;/code&gt;, &lt;code&gt;RefreshToken&lt;/code&gt;) for each successful login request. There is a fair chance that your application would use these tokens to &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;secure API requests.&lt;/li&gt;
&lt;li&gt;manage permissions/roles based authorization to the resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;amp; other custom authorization requirements.&lt;br&gt;
Usually, &lt;code&gt;IDToken&lt;/code&gt; &amp;amp; &lt;code&gt;AccessToken&lt;/code&gt; are verified for such purposes, but not &lt;code&gt;RefreshToken&lt;/code&gt;. It is there just to refresh the session.&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;IDToken&lt;/code&gt; &amp;amp; &lt;code&gt;AccessToken&lt;/code&gt; have some common as well as unique claims so its 100% your own choice to decide where to verify which token according to your use-case.&lt;/p&gt;

&lt;p&gt;More on using Tokens &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Find &lt;strong&gt;Cognito JWT Verification Algorithm&lt;/strong&gt; here 👉 &lt;a href="https://gist.github.com/afraz-khan/65ebd02326480ac96e4ef9c066e0dbea"&gt;github-gist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use same algorithm with minor additions/deletions to verify both &lt;code&gt;IDToken&lt;/code&gt; &amp;amp; &lt;code&gt;AccessToken&lt;/code&gt;. This algorithm is written in TypeScript and follows the steps as described in officical Cognito guide &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html"&gt;here&lt;/a&gt; to verify the JWTs.&lt;/p&gt;

&lt;p&gt;cheers :)&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cognito</category>
      <category>jwt</category>
      <category>security</category>
    </item>
    <item>
      <title>Refresh Tokens</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Sat, 01 Jan 2022 23:20:38 +0000</pubDate>
      <link>https://forem.com/afrazkhan/refresh-tokens-173d</link>
      <guid>https://forem.com/afrazkhan/refresh-tokens-173d</guid>
      <description>&lt;p&gt;In OAuth implementation, &lt;strong&gt;Authorization/Resource&lt;/strong&gt; server assigns an &lt;a href="https://oauth.net/2/access-tokens/"&gt;AccessToken&lt;/a&gt; to each successfull user session. &lt;code&gt;AccessToken&lt;/code&gt; is used by the client to make requests to the resource server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RefreshToken&lt;/strong&gt; is issued to the client by the authorization server to obtain a new &lt;code&gt;AccessToken&lt;/code&gt; when the current &lt;code&gt;AccessToken&lt;/code&gt; becomes invalid or expires or to obtain additional AccessTokens with an identical or narrower scope. Basically, &lt;code&gt;RefreshToken&lt;/code&gt; provides the clients with a smooth experience where users are not required to repeat login step or some other authentication flow in order to get new &lt;code&gt;AccessToken&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;References&lt;br&gt;
&lt;a href="https://datatracker.ietf.org/doc/html/rfc6749#section-1.5"&gt;IETF&lt;/a&gt;&lt;br&gt;
&lt;a href="https://oauth.net/2/access-tokens/"&gt;oauth.net&lt;/a&gt;&lt;br&gt;
&lt;a href="https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/"&gt;oauth0.com&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use Refresh-Token?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;After each successfull authentication request, Authorization/Resource server must generate 2 JWT tokens (AccessToken , RefreshToken). &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I talk here with &lt;a href="https://datatracker.ietf.org/doc/html/rfc7519"&gt;JWT&lt;/a&gt; specification under consideration but tokens can be either JWTs or some other format of your choice. Its an implementation decision and not a topic to emphasize-on in this post.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Client will save both of the JWT tokens in the browser at some safe place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;RefreshToken&lt;/code&gt; JWT would have longer expiry (maybe 1 day) than &lt;code&gt;AccessToken&lt;/code&gt;(could be 1-3 hours).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When &lt;code&gt;AccessToken&lt;/code&gt; expires, the webapp/client would hit &lt;code&gt;/api/auth/token&lt;/code&gt; endpoint with &lt;code&gt;RefreshToken&lt;/code&gt; in request payload. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;/api/auth/token&lt;/strong&gt;&lt;/em&gt; is supposed to issue new AccessTokens.&lt;br&gt;
Client does this silently without alerting the user.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The system will verify the &lt;code&gt;RefreshToken&lt;/code&gt; and issue a new &lt;code&gt;AccessToken&lt;/code&gt; without any user interaction involved.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BtxIhQj0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bc0ossilvir3ab6mrlz0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BtxIhQj0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bc0ossilvir3ab6mrlz0.jpeg" alt="refresh-tokens" width="780" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  RefreshToken Revocation
&lt;/h3&gt;

&lt;p&gt;RefreshToken JWTs usually remain valid for longer durations like 1 day, 1 week or so and there is a chance that token could be compromised and misused beyond the user logout action if unexpired. To mitigate this potential threat, there should be some mechanism in place to invalidate the revoked but unexpired JWTs.&lt;/p&gt;

&lt;p&gt;Some techniques are mentioned below:&lt;/p&gt;

&lt;h4&gt;
  
  
  JWT Whitelist
&lt;/h4&gt;

&lt;p&gt;Here, the system maintains a whitelist of active RefreshTokens in some in-memory cache or database.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every time a new &lt;code&gt;RefreshToken&lt;/code&gt; request comes, the system looks for incoming &lt;code&gt;RefreshToken&lt;/code&gt; in the in-memory cache or database.&lt;/li&gt;
&lt;li&gt;If found, the system issues a new &lt;code&gt;AccessToken&lt;/code&gt; else invalidates the request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;references: &lt;a href="https://www.izertis.com/en/-/refresh-token-with-jwt-authentication-in-node-js"&gt;1&lt;/a&gt;, &lt;a href="https://www.bezkoder.com/jwt-refresh-token-node-js/"&gt;2&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=ssypjWFdD4E&amp;amp;ab_channel=yoursTRULY"&gt;3&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  JWT Blacklist
&lt;/h4&gt;

&lt;p&gt;Here, the system maintains a blacklist of old/revoked refresh tokens in some in-memory cache or database. Revoked Tokens live on the blacklist until their expiry time is reached. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every time a new refresh token request comes, the system looks for incoming &lt;code&gt;RefreshToken&lt;/code&gt; in the in-memory cache or database.&lt;/li&gt;
&lt;li&gt;If found, that means, the incoming &lt;code&gt;RefreshToken&lt;/code&gt; is revoked and the system invalidates the request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;references: &lt;a href="https://auth0.com/blog/denylist-json-web-token-api-keys/"&gt;1&lt;/a&gt;, &lt;a href="https://auth0.com/docs/security/tokens/refresh-tokens/refresh-token-rotation#automatic-reuse-detection"&gt;2&lt;/a&gt;, &lt;a href="https://stackoverflow.com/a/40385939/8823192"&gt;3&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Unique Claims
&lt;/h4&gt;

&lt;p&gt;Every JWT has a claims list with it that includes information provided by user (&lt;code&gt;email&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;) as well as some attributes required by &lt;a href="https://datatracker.ietf.org/doc/html/rfc7519#page-8"&gt;JWT Specification&lt;/a&gt; (&lt;code&gt;iat&lt;/code&gt;, &lt;code&gt;sub&lt;/code&gt;).&lt;br&gt;
You can use any claim out of the JWT specification list to ensure token's authenticity. Use below technique:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Choose a token claim that is always unique at the time of token issuance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;JWT &lt;code&gt;iat&lt;/code&gt; is best option as its a unix time stamp.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Introduce a new field in your &lt;code&gt;User&lt;/code&gt; database table where system will save the value of that claim for each new &lt;code&gt;RefreshToken&lt;/code&gt; that system generates for each login request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When system recieves a request to refresh the &lt;code&gt;AccessToken&lt;/code&gt;. System will verify if &lt;code&gt;iat&lt;/code&gt; value of incoming &lt;code&gt;RefreshToken&lt;/code&gt; matches the current &lt;code&gt;iat&lt;/code&gt; against the current user in the database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If both &lt;code&gt;iat&lt;/code&gt; values match then system issues new pair of &lt;code&gt;AccessToken&lt;/code&gt; and &lt;code&gt;RefreshToken&lt;/code&gt; otherwise &lt;code&gt;401&lt;/code&gt; throws exception.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Some Stateless techniques
&lt;/h4&gt;

&lt;p&gt;In the above 2 methods, database queries are involved to check the JWT revocation and this makes the token stateful. But depending on the severity of the JWT compromise that one foresees, there are many techniques out there to avoid any unwanted activity using stateless JWTs. &lt;br&gt;
2 of them described below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Short Expiry times&lt;/strong&gt;&lt;br&gt;
The straightforward stateless solution enforces the use of short expiry times for both &lt;code&gt;AccessToken&lt;/code&gt; and &lt;code&gt;RefreshToken&lt;/code&gt; like 10min expiry for &lt;code&gt;AccessToken&lt;/code&gt; and 1hr expiry for &lt;code&gt;RefreshToken&lt;/code&gt;. This simply reduces the time for any malicious activity if occurred.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User-Defined Secret&lt;/strong&gt;&lt;br&gt;
For each user, use a different secret to sign the &lt;code&gt;RefreshToken&lt;/code&gt; JWT like &lt;code&gt;secret = ENV.secret + user.password&lt;/code&gt; while generating the &lt;code&gt;RefreshToken&lt;/code&gt;. At any time, if &lt;code&gt;RefreshToken&lt;/code&gt; of a particular user is compromised, ask that user to reset their &lt;code&gt;password&lt;/code&gt; and all old RefreshTokens issued to that user would be revoked automatically. &lt;br&gt;
See implementation: &lt;a href="https://www.youtube.com/watch?v=UA0AIkjI85c&amp;amp;ab_channel=BenAwad"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I hope this helps 🙂.&lt;/p&gt;

</description>
      <category>jwt</category>
      <category>authorization</category>
      <category>oauth2</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Python WSGI Applications</title>
      <dc:creator>Afraz Khan</dc:creator>
      <pubDate>Mon, 18 Oct 2021 09:49:49 +0000</pubDate>
      <link>https://forem.com/afrazkhan/python-wsgi-applications-1kjb</link>
      <guid>https://forem.com/afrazkhan/python-wsgi-applications-1kjb</guid>
      <description>&lt;p&gt;Http requests in python web applications are served as shown below&lt;/p&gt;

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

&lt;p&gt;Web developers usually work with the web frameworks like Django, flask, but they hardly know the actual mechanics in place about how http requests float through the system and how the desired http response is generated.&lt;br&gt;
A web framework is a major component of the whole process. These days, applications are written mostly under the web frameworks, but as a developer, its very essential to have the knowledge of each component of the request -&amp;gt; resposne cycle and in python web apps, &lt;strong&gt;WSGI&lt;/strong&gt; is very important concept that you will learn in this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some History
&lt;/h3&gt;

&lt;p&gt;Before moving to WSGI details, I find that short look of history would be vital so lets start from when the web came into being.&lt;/p&gt;

&lt;p&gt;Web or HTTP is static, by design this means it can only return you a static file on the server. Let's say, a web server receives a request as shown in below image &lt;code&gt;GET /index.html&lt;/code&gt;. The server finds that page on the disk, reads &lt;code&gt;index.html&lt;/code&gt; file and returns a response with content of &lt;code&gt;index.html&lt;/code&gt; file. Web could also return CSS files or other static assets, but the whole idea back then was simple like this.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  External Scripts
&lt;/h4&gt;

&lt;p&gt;By early 90's, it was identified that the web was not an efficient and interactive way to entertain the dynamic http requests where each request doesn't have to update static html pages every time. Some dynamic method was needed to process inputs like html forms, sessions. &lt;/p&gt;

&lt;p&gt;That was achieved by running external scripts that would process those new input types, i.e. html-forms, json(later).&lt;/p&gt;

&lt;p&gt;At that time, external scripts were written in PERL or PHP, but it was doable with python also. External scripts were  named after the input they used to process like &lt;code&gt;form.py&lt;/code&gt;, &lt;code&gt;json.py&lt;/code&gt;. &lt;code&gt;form.py&lt;/code&gt; would process form-data and &lt;code&gt;json.py&lt;/code&gt; would process json-data. Now, instead of sending bear metal file names in requests like &lt;code&gt;GET /index.html&lt;/code&gt;. Web servers started to get requests as &lt;code&gt;GET form.py&lt;/code&gt;. That used to indicate that server has to run &lt;code&gt;form.py&lt;/code&gt; that is an external script to process an html form request.&lt;br&gt;
Web server used to fork the parent process and run the scripts. Any &lt;code&gt;print()&lt;/code&gt; statement in external scripts turned out to be the http response to the client.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  CGI (Common Gateway Interface)
&lt;/h4&gt;

&lt;p&gt;Web servers usually parse a http request, create some new environment variables and external scripts inherit them in the arguments. But different web servers named randomly to those environment variables that caused conflicts. Each server had its own specification of environment variables. &lt;/p&gt;

&lt;p&gt;To mitigate this, a common standard for request environment variables was established named Common Gateway Interface.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  WSGI
&lt;/h3&gt;

&lt;p&gt;Python community took a step ahead and along with CGI environment variables, they standardized the way, external scripts must be executed. This standardization was named as &lt;strong&gt;WSGI(Web Server Gateway Interface)&lt;/strong&gt;. It is described in python doc &lt;a href="https://www.python.org/dev/peps/pep-3333/" rel="noopener noreferrer"&gt;PEP 3333&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;This specification ensures that every python external script called from a web server must have a particular callable object (class/ method/ function/ instance having &lt;code&gt;__call__&lt;/code&gt; method) as below:&lt;/p&gt;

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

&lt;p&gt;There are 2 sides of WSGI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Application/Framework&lt;/strong&gt;: Python web frameworks actually act as external scripts that conform to the WSGI protocol by implementing a callable object as described in above figure. WSGI compatible servers execute this object for each request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server/Gateway&lt;/strong&gt;: WSGI servers implement the functionality to execute the callable object. Web servers like Apache, Nginx are not able to do this task so intermediate servers like gunicorn, uWSGI play the part in between. They take http requests from web servers, call the WSGI object with the request and send back the response to web servers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Power of WSGI servers is that, a python web application built in any python framework can use any WSGI server like gunicorn, uWSGI. Python developers can write future web servers/ web frameworks using WSGI specification so that web server or web framework would be portable to any other available option.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Some more about WSGI Web Servers
&lt;/h3&gt;

&lt;h4&gt;
  
  
  - No Interpreter Restart
&lt;/h4&gt;

&lt;p&gt;Going back to CGI external scripts for a moment. There is a limitation with external scripts that, for each new request, web server has to restart the python interpreter and run the script. This slows down the process a lot.&lt;br&gt;
One of the potential benefits of the WSGI server is that now web server doesn't have to spin-up the new python interpreter for each new request. Instead the web server passes the request to WSGI server that runs the WSGI callable object/function repeatedly for each request. This approach is way more robust.&lt;/p&gt;

&lt;h4&gt;
  
  
  - Pre-Forking
&lt;/h4&gt;

&lt;p&gt;One bottleneck is the time web servers take to create a new process for each request in order to execute the callable object.&lt;br&gt;
Pre-forking is a technique where web servers pre fork the external script processes in idle time or in python world, WSGI servers create new processes beforehand to run the callable object against each http request. These processes are called workers, you can even create threads to those workers.&lt;br&gt;
HTTP servers like Nginx can't pre-fork so that's also another reason to fit in the WSGI servers in between Nginx and python web applications.&lt;/p&gt;




&lt;p&gt;for more, visit the links &lt;a href="https://www.python.org/dev/peps/pep-3333/" rel="noopener noreferrer"&gt;1&lt;/a&gt; &lt;a href="http://wsgi.tutorial.codepoint.net/" rel="noopener noreferrer"&gt;2&lt;/a&gt; &lt;a href="http://wsgi.tutorial.codepoint.net/intro#" rel="noopener noreferrer"&gt;3&lt;/a&gt;&lt;br&gt;
hope you learnt something :)&lt;/p&gt;

</description>
      <category>python</category>
      <category>wsgi</category>
      <category>webdev</category>
      <category>http</category>
    </item>
  </channel>
</rss>
