<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Laslo Pastor</title>
    <description>The latest articles on DEV Community by Laslo Pastor (@lpastor74).</description>
    <link>https://dev.to/lpastor74</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%2F1202755%2F97bc2689-7fc7-4f0e-8f49-ac63d912164c.jpeg</url>
      <title>DEV Community: Laslo Pastor</title>
      <link>https://dev.to/lpastor74</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lpastor74"/>
    <language>en</language>
    <item>
      <title>Azure AD as a federated key manager for the WSO2 API gateway</title>
      <dc:creator>Laslo Pastor</dc:creator>
      <pubDate>Fri, 12 Dec 2025 17:43:36 +0000</pubDate>
      <link>https://dev.to/lpastor74/azure-ad-as-a-federated-key-manager-for-the-wso2-api-gateway-42o4</link>
      <guid>https://dev.to/lpastor74/azure-ad-as-a-federated-key-manager-for-the-wso2-api-gateway-42o4</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;The need for an API Management (APIM) layer and a well-structured segmentation architecture within an organization is something most architects agree on. However, having the luxury of building a fully greenfield APIM environment from scratch is rare. In reality, most enterprises already operate legacy web services or APIs built years ago, which makes introducing a modern APIM platform a challenging process.&lt;/p&gt;

&lt;p&gt;One of the first hurdles often faced is integration with existing Identity Providers (IdPs). Establishing a secure token exchange mechanism that the API Gateway can trust is essential, but it is not always straightforward.&lt;/p&gt;

&lt;p&gt;A modern APIM solution should therefore offer a flexible architecture that supports horizontal scaling, fine-grained access control, and seamless identity integration using the organization’s existing IdP ecosystem.&lt;/p&gt;

&lt;p&gt;WSO2 API Manager 4.6 addresses this challenge by natively supporting external identity providers such as Auth0, Azure AD, Keycloak, Okta, Ping Identity, and, of course, WSO2 Identity Server, along with any other IdP that supports OAuth2/OIDC.&lt;/p&gt;

&lt;p&gt;This article examines the technical aspects and configuration details for integrating Azure AD as a Key Manager with the WSO2 API Manager Gateway, aiming to make the setup process as seamless as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requests
&lt;/h2&gt;

&lt;p&gt;My client already had Azure AD B2C in place and wanted to use it as a Key Manager for the WSO2 API Manager Gateway (APIM GW). In addition, they preferred to leverage a preconfigured application instead of creating a new one from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;WSO2 provides comprehensive documentation to help you get started with this setup &lt;a href="https://apim.docs.wso2.com/en/latest/administer/key-managers/configure-azure-ad-key-manager/" rel="noopener noreferrer"&gt;Configure AzureAD as Key Manager&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Note 1
&lt;/h4&gt;

&lt;p&gt;You’ll need an application in Azure that acts as a connector between WSO2 API Manager and Azure AD. This application must have the following permissions assigned:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Application.Read.All&lt;br&gt;
Application.ReadWrite.All&lt;br&gt;
Application.ReadWrite.OwnedBy&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Although these permissions are mentioned in the official documentation, it’s worth emphasizing that missing any of them will prevent APIM from creating or locating applications within your Azure environment, causing the configuration to fail.&lt;/p&gt;
&lt;h4&gt;
  
  
  Note 2
&lt;/h4&gt;

&lt;p&gt;Setting up a new Key Manager in the WSO2 Admin Portal is the first challenge you’ll need to overcome.&lt;br&gt;
From the dropdown list of available Key Manager Types, select Azure AD, and ensure that at least the Direct Token Issuance method is enabled.&lt;/p&gt;

&lt;p&gt;You can find the relevant endpoint information under the Endpoints section in your Azure AD application. &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%2Flwjows1wh1l7qsuri9nn.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%2Flwjows1wh1l7qsuri9nn.png" alt=" " width="800" height="188"&gt;&lt;/a&gt;&lt;br&gt;
However, keep in mind that while many fields in the WSO2 configuration are mandatory, Azure AD does not utilize all of them. As a result, some fields may appear redundant and can remain unused. Your configuration fields should look similar to the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Well-known URL&lt;/strong&gt;  , mandatory&lt;br&gt;
(Paste the OpenID Connect metadata document (v2.0) URL collected from the endpoints and click on Import)&lt;br&gt;
In my case :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://login.microsoftonline.com/{tenantID}/v2.0/.well-known/openid-configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Issuer&lt;/strong&gt; , mandatory&lt;br&gt;
(in documentation example is &lt;a href="https://login.microsoftonline.com/%7Btenent-id%7D/v2.0" rel="noopener noreferrer"&gt;https://login.microsoftonline.com/{tenent-id}/v2.0&lt;/a&gt;). If you leave it like that will fail becouse token issuer in reality looks like '&lt;a href="https://sts.windows.net/%7Btenent-id%7D/" rel="noopener noreferrer"&gt;https://sts.windows.net/{tenent-id}/&lt;/a&gt;'&lt;br&gt;
In my case,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://sts.windows.net/{tenent-id}/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Client Registration Endpoint&lt;/strong&gt; , mandatory&lt;br&gt;
In my case:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Introspection Endpoint&lt;/strong&gt;, marked as mandatory, but AzureAd does not use it &lt;br&gt;
I put:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://login.microsoftonline.com/{tenent-id}/oauth2/v2.0/token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Token Endpoint&lt;/strong&gt;, mandatory &lt;br&gt;
In my case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://login.microsoftonline.com/{tenent-id}/oauth2/v2.0/token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Revoke Endpoint&lt;/strong&gt;, marked as mandatory, but AzureAd does not use it &lt;br&gt;
I put (again):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://login.microsoftonline.com/{tenent-id}/oauth2/v2.0/token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Userinfo Endpoint&lt;/strong&gt;, mandatory &lt;br&gt;
In my case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://graph.microsoft.com/oidc/userinfo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Authorize Endpoint&lt;/strong&gt;, not mandatory&lt;br&gt;
In my case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://login.microsoftonline.com/{tenent-id}/oauth2/v2.0/authorize
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Scope Management Endpoint&lt;/strong&gt;, in the form, it is marked as mandatory, even though the documentation doesn’t clearly explain its purpose, and in practice, it doesn’t seem to be used. I entered the scope required when requesting a token, but in reality, any value will work without affecting functionality.&lt;br&gt;
In my case:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;blockquote&gt;
&lt;p&gt;Also, for clarity: wherever you see {tenantID} in the endpoint URLs mentioned above, make sure to replace it with your actual Azure tenant ID.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The rest of the steps you can follow from the documentation &lt;br&gt;
Fill the Consumer Key Claim URI: &lt;strong&gt;appid&lt;/strong&gt; in the Claim URIs section.&lt;br&gt;
Set the Grant Types: &lt;strong&gt;client_credentials&lt;/strong&gt; (Only use this grant type).&lt;/p&gt;

&lt;p&gt;Microsoft Graph API Endpoint:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Microsoft Graph API Endpoint Version, select the checkbox for v1.0&lt;br&gt;
Client ID   : Paste the Application (client) ID&lt;br&gt;
Client Secret   : Paste the client secret value that is generated&lt;/p&gt;

&lt;p&gt;Key Manager Permission: Permission type for role-based Key Manager restriction.&lt;br&gt;
e.g., PUBLIC, ALLOW, DENY &lt;/p&gt;
&lt;h4&gt;
  
  
  Note 3
&lt;/h4&gt;

&lt;p&gt;After completing these steps, you can navigate to the WSO2 Developer Portal to create an application, generate keys (Client ID and Secret), subscribe to an API, and obtain an access token. Once you invoke the API, the call should return a 200 OK response confirming that everything is working as expected.&lt;/p&gt;

&lt;p&gt;Congratulations, you’re on the right track and officially halfway there!&lt;/p&gt;
&lt;h4&gt;
  
  
  Note 4
&lt;/h4&gt;

&lt;p&gt;To enable the option for out-of-band keys, allowing you to use an existing application previously created in Azure, open the /repository/conf/deployment.toml file in a text editor.&lt;br&gt;
Add the following configuration under the [apim.devportal] section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[apim.devportal]
enable_key_provisioning = true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After restarting the server, you’ll be able to register applications in the Developer Portal using the Client ID and Client Secret that were previously created in Azure.&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%2Fv8pi3eb9u2dcvritttsb.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%2Fv8pi3eb9u2dcvritttsb.png" alt=" " width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Note 5
&lt;/h4&gt;

&lt;p&gt;When you create an application in Azure, the Application ID URI field is empty by default. This causes a problem, tokens generated from such an application will fail, returning an error indicating that the application cannot be found under the specified tenant.&lt;/p&gt;

&lt;p&gt;To fix this, make sure to define the Application ID URI in the following format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;api://&amp;lt;Application (client) ID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although this step is briefly mentioned in the post-check section of the documentation, it isn’t clearly explained where to find or configure it. So, take a moment to verify this setting before proceeding — it will save you unnecessary troubleshooting later.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;If you run into any issues or discover new challenges along the way, feel free to share them in the comments — I’d love to hear your experiences and help if I can.&lt;/p&gt;

</description>
      <category>wso2</category>
      <category>apim</category>
      <category>azure</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building a Customer Data Nerve Center with Twilio Segment, WSO2, and Asgardeo</title>
      <dc:creator>Laslo Pastor</dc:creator>
      <pubDate>Sat, 23 Aug 2025 04:09:57 +0000</pubDate>
      <link>https://dev.to/lpastor74/building-a-customer-data-nerve-center-with-twilio-segment-wso2-and-asgardeo-4aoj</link>
      <guid>https://dev.to/lpastor74/building-a-customer-data-nerve-center-with-twilio-segment-wso2-and-asgardeo-4aoj</guid>
      <description>&lt;p&gt;In today’s world, data isn’t just an asset but a continuous thread connecting every customer interaction. Whether a customer is browsing your website, chatting with support, or completing a purchase, their journey should feel like one continuous story. The challenge? Ensuring that the story remains consistent, secure, and compliant across every channel.&lt;/p&gt;

&lt;p&gt;One powerful approach is to orchestrate Twilio Segment (for customer data collection), WSO2 (for integration and API governance), and Asgardeo (for identity and consent management). Together, they form an identity-first data pipeline, a central nervous system that feeds analytics, personalization engines, and even an AI-driven decision engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reference Architecture
&lt;/h2&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%2Fpxjvndq4cjeuyxxn5cq1.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%2Fpxjvndq4cjeuyxxn5cq1.png" alt=" " width="800" height="558"&gt;&lt;/a&gt;&lt;br&gt;
Think of this setup like the scout battleship that continuously senses, interprets, and routes signals across the enterprise.&lt;br&gt;
    • Twilio Segment: Captures events from websites, apps, and backend systems, from page views to purchases. Profiles evolve from anonymous to verified identities once a login happens.&lt;br&gt;
    • Asgardeo: Secures that identity with SSO and MFA, while governing consent preferences to ensure privacy.&lt;br&gt;
    • WSO2 API Manager: Acts as the deflector shield, validating and securing every inbound request before it touches core systems.&lt;br&gt;
    • WSO2 Micro Integrator: Orchestrates data flows, enriching raw events with business context (e.g., CRM details, product metadata) before routing them to downstream consumers (data warehouse, marketing automation, or analytics platform).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;With this approach, customer profiles stay consistent across all channels. Compliance is built into the process, with consent preferences enforced at the identity layer. And each team in your organization can get the data they need in the tools they already use, without fragile point-to-point integrations.&lt;br&gt;
The result: less friction, fewer silos, and more agility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current Limitations
&lt;/h2&gt;

&lt;p&gt;As always, there are challenges.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Anonymous activity is hard to connect to a known customer until they log in, which can leave profiles incomplete. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consent changes in one channel might not appear instantly across all systems. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Without careful governance, there’s a risk of collecting more data than necessary or capturing sensitive information without permission.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adding routing and enrichment, and orchestration steps can introduce a delay for real-time personalization.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where AI Can Help
&lt;/h2&gt;

&lt;p&gt;AI has the potential to make this architecture smarter and more proactive.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI can improve identity discovery, linking anonymous activity to known profiles by recognizing patterns in behavior. &lt;/li&gt;
&lt;li&gt;AI can create dynamic customer segments based on predicted data or mitigate the risk, rather than static definitions. &lt;/li&gt;
&lt;li&gt;AI can recognize unusual patterns in the data flow, such as a sudden drop in conversions, and create an alert before it becomes a bigger issue.&lt;/li&gt;
&lt;li&gt;AI-driven engines with fresh customer data can personalize offers and content in real time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;p&gt;Looking ahead, there’s room to make this architecture even more powerful.&lt;/p&gt;

&lt;p&gt;Real-time feedback loops could be made even faster, delivering insights in milliseconds instead of minutes. Consent could be managed through a single, unified service that updates instantly across every connected system. AI could play a bigger role in governance, automatically flagging irrelevant or risky data fields before they cause problems. And eventually, the pipelines themselves could adjust automatically, optimizing data flows based on business priorities and performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&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%2Fq4tgau8xkdnl2mk5o7jl.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%2Fq4tgau8xkdnl2mk5o7jl.png" alt=" " width="800" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The real magic happens when you connect this architecture to an AI-powered future. Right now, Twilio Segment, Asgardeo, and WSO2 ensure that customer data is accurate, secure, and delivered where it needs to be. But when you add Apache Kafka as the real-time backbone, the game changes.&lt;/p&gt;

&lt;p&gt;Kafka allows enriched events from WSO2 Micro Integrator to be streamed instantly to any number of systems. That means marketing platforms, analytics dashboards, personalization engines, and AI models can all tap into the same live data without slowing each other down. Adding or replacing a data consumer becomes a matter of configuration, not an integration project.&lt;/p&gt;

&lt;p&gt;From there, the Analytics and AI layer, powered by platforms like Snowflake, Databricks, or Google BigQuery, turns this data stream into insight and action. AI models trained on historical and real-time data can predict customer churn, recommend next-best actions, flag anomalies in user behavior, or identify high-value prospects before they’re even on your radar.&lt;/p&gt;

&lt;p&gt;The benefits are tangible:&lt;br&gt;
    • Marketing campaigns can adjust automatically when engagement patterns shift.&lt;br&gt;
    • Support teams can proactively reach out to customers showing early signs of dissatisfaction.&lt;br&gt;
    • Product teams can make design or feature decisions backed by live usage data rather than waiting for quarterly reports.&lt;/p&gt;

&lt;p&gt;Instead of simply reporting on what happened, the system evolves into an anticipation engine that predicts needs and enables the business to respond in the moment. Kafka ensures that the right data is always in motion, and AI ensures that every piece of it is turned into intelligence that drives results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Combining Twilio Segment for data collection, Asgardeo for identity and consent, and WSO2 for secure integration creates a scalable, compliant, and future-ready customer data platform. Add Kafka for real-time event streaming and an AI-powered analytics layer, and the system becomes far more than a pipeline — it becomes a proactive decision-making engine that helps you understand, anticipate, and delight customers at every step of their journey.&lt;/p&gt;

</description>
      <category>ciam</category>
      <category>wso2</category>
      <category>idp</category>
      <category>iam</category>
    </item>
    <item>
      <title>Integration thought iteration-The not Bad, the OK, and the Good Enough</title>
      <dc:creator>Laslo Pastor</dc:creator>
      <pubDate>Sat, 13 Apr 2024 21:52:02 +0000</pubDate>
      <link>https://dev.to/lpastor74/integration-thought-iteration-the-bad-the-ugly-and-the-good-enough-329b</link>
      <guid>https://dev.to/lpastor74/integration-thought-iteration-the-bad-the-ugly-and-the-good-enough-329b</guid>
      <description>&lt;p&gt;In response to a recent request to enhance the pickup system for a transport and storage company, I embarked on a series of iterations to develop viable solutions. This article delves into the evolution of ideas and presents three potential solutions that were considered before identifying the one deemed "good enough" for implementation. &lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;A storage company operates multiple locations where products are stored. When they receive shipping requirements, they must gather pickup orders from various locations to fulfill the required quantities of each product. The individual responsible for creating the pickup list must determine the closest storage location and verify if there is a sufficient quantity of the required product available. If the required quantity is not available, they need to check the next storage location until the quantity requirement is met. This process must be repeated for every product on the list.&lt;/p&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%2F0vpoahpwcylgodmy1eh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0vpoahpwcylgodmy1eh0.png" alt="Image description" width="543" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution 'not Bad' - The first iteration
&lt;/h2&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%2Fcue8c781u317o55c6hlu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcue8c781u317o55c6hlu.png" alt="Image description" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Exposing database data as a REST Data Service offers significant benefits, providing a straightforward way to access and manipulate data. Additionally, calling SQL procedures as a REST resource facilitates seamless integration into applications, simplifying the development process and enhancing overall efficiency.&lt;br&gt;
However, ensuring controlled and secure access for external users requires the utilization of API management gateways.&lt;/p&gt;

&lt;p&gt;The primary enhancement was implementing an SQL procedure that utilizes ZIP code search to locate the nearest storage facilities and populate the pickup list until a sufficient quantity of the requested product is not found.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CREATE DEFINER=&lt;/code&gt;db_753&lt;code&gt;@&lt;/code&gt;73.232.207.137&lt;code&gt;PROCEDURE&lt;/code&gt;cloud_demo&lt;code&gt;.&lt;/code&gt;orderList`(IN productID INT, IN zip CHAR(5), IN qty DECIMAL(5,2))&lt;br&gt;
BEGIN&lt;br&gt;
    DECLARE done BOOLEAN DEFAULT FALSE;&lt;br&gt;
    DECLARE c_zip VARCHAR(5);&lt;br&gt;
    DECLARE c_address VARCHAR(255);&lt;br&gt;
    DECLARE c_product_name VARCHAR(255);&lt;br&gt;
    DECLARE c_quantity DECIMAL(5, 2); &lt;br&gt;
    DECLARE totalQuantity DECIMAL(10, 2) DEFAULT 0.00;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DECLARE orderCursor CURSOR FOR
     select s.Qty, s2.zip, s2.Address,p.Name from 
     Stock s inner join Product p on s.product_id = p.id inner JOIN Storage s2 on s.storage_id = s2.id 
     where p.id = productID and s2.zip like zip
     ORDER by s.Qty DESC, s2.zip;

-- Declare handler for cursor
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

-- Temporary table to store product quantities
CREATE TEMPORARY TABLE IF NOT EXISTS tempProductQuantityPerZip ( 
    t_prod_quantity DECIMAL(5,2),
    t_zip VARCHAR(5),
    t_address VARCHAR(255),
    t_product_name VARCHAR(255)
);  

Delete FROM tempProductQuantityPerZip;
set totalQuantity = 0;

-- Open cursor
OPEN orderCursor; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;-- Start iterating over the returned list&lt;br&gt;
    read_loop: LOOP&lt;br&gt;
        -- Fetch data from cursor into variables&lt;br&gt;
        FETCH orderCursor INTO c_quantity,c_zip,c_address,c_product_name;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    -- Check if cursor has reached the end of the result set
    IF done THEN
        LEAVE read_loop;
    END IF;

    IF totalQuantity &amp;lt; qty then
     INSERT into tempProductQuantityPerZip(t_prod_quantity,t_zip,t_address,t_product_name) VALUES (c_quantity,c_zip,c_address,c_product_name);
    END IF;

   SET totalQuantity = totalQuantity + c_quantity;

 END LOOP read_loop;

-- Close cursor
CLOSE orderCursor;

Select * from tempProductQuantityPerZip;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;END`&lt;/p&gt;

&lt;p&gt;To create RDBMS Datasource, I used &lt;a href="https://mi.docs.wso2.com/en/latest/learn/examples/data-integration/rdbms-data-service/"&gt;WSO2 MI&lt;/a&gt;&lt;br&gt;
full db script can be found in the &lt;a href="https://github.com/lpastor74/shoping"&gt;GitRepository&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution 'the OK' - The second iteration
&lt;/h2&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%2F2ayu2scyxoetpmq21sp7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ayu2scyxoetpmq21sp7.png" alt="Image description" width="790" height="313"&gt;&lt;/a&gt;&lt;br&gt;
The primary issue with the initial solution is its limitation to process only one product request at a time. Furthermore, in the event of a database unavailability, requests may be lost. To address this, the new solution introduces an additional API that exposes an integration synapse named 'callDataService', enabling the handling of multiple product requests simultaneously.(with &lt;a href="https://mi.docs.wso2.com/en/latest/reference/mediators/iterate-mediator/"&gt;Iteration mediator&lt;/a&gt;). &lt;br&gt;
To enhance resilience, the new API exposes a resource that stores requests in the Kafka message queue.(used &lt;a href="https://mi.docs.wso2.com/en/latest/reference/connectors/kafka-connector/kafka-connector-config"&gt;Kafka connector&lt;/a&gt;), using a &lt;a href="https://mi.docs.wso2.com/en/latest/reference/connectors/kafka-connector/kafka-inbound-endpoint-example/"&gt;Kafka inbound endpoint&lt;/a&gt;, a specific topic is monitored to direct received message to the 'callDataService' integration.&lt;br&gt;
The final challenge arose from receiving an array of information containing product IDs, quantities, and store details, request was to group this information by storage location and list the products to be picked from each location. For this we used &lt;br&gt;
&lt;a href="https://mi.docs.wso2.com/en/latest/reference/mediators/script-mediator/"&gt;Script mediator&lt;/a&gt; (Big thanks goes to Arunan Sugunakumar).&lt;br&gt;
The final addition was the development of the 'sendEmail' integration synapse, which accepts the payload, iterates through it, and sends an email to each store with information regarding the products and quantities that need to be prepared for pickup.(used &lt;a href="https://mi.docs.wso2.com/en/latest/reference/connectors/email-connector/email-connector-config/"&gt;Email connector&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution 'Good Enough' - The third iteration
&lt;/h2&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%2Fru7j8jrz5019ses4ovb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fru7j8jrz5019ses4ovb9.png" alt="Image description" width="765" height="293"&gt;&lt;/a&gt;&lt;br&gt;
Ultimately, to accommodate the final requirement of enabling requests through a JSON file dropped in an FTP location, I implemented an SFTP watcher. This watcher monitors files with a .json extension, parses them, and then sends them to a Kafka message queue.&lt;br&gt;
To achieve I used &lt;a href="https://mi.docs.wso2.com/en/latest/learn/examples/inbound-endpoint-examples/file-inbound-endpoint/"&gt;File inbound endpoint connector&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Note: don't forget to URL encode your password when creating a connection string (it took me a while to figure out why my connection wasn't working)&lt;/p&gt;

&lt;p&gt;Summary:&lt;br&gt;
All connectors used in the solution and much more can be found on th &lt;a href="https://store.wso2.com/store/pages/top-assets"&gt;WSO2 store&lt;/a&gt;.&lt;br&gt;
The whole MI solution can be found on &lt;a href="https://github.com/lpastor74/shoping"&gt;GitRepository&lt;/a&gt;.&lt;br&gt;
The journey of refining and enhancing your solution knows no bounds, and it all begins with that very first step. And as Gandalf the Gray said: "..It's a dangerous business, going out your door. You step onto the road, and if you don't keep your feet, there's no knowing where you might be swept off to..."&lt;/p&gt;

</description>
      <category>wso2</category>
      <category>ei</category>
      <category>integration</category>
      <category>ballerina</category>
    </item>
    <item>
      <title>Identity events and conditional authentication</title>
      <dc:creator>Laslo Pastor</dc:creator>
      <pubDate>Wed, 10 Apr 2024 02:03:15 +0000</pubDate>
      <link>https://dev.to/lpastor74/identity-events-and-conditional-authentication-2hi3</link>
      <guid>https://dev.to/lpastor74/identity-events-and-conditional-authentication-2hi3</guid>
      <description>&lt;p&gt;In today's fast-paced digital landscape, application developers face a hard job: meeting high business demands while ensuring a seamless and secure login experience. The task becomes even more challenging when considering the need for resilience, ease of implementation, scalability, and adherence to tight timeframes. &lt;br&gt;
Modern Identity and Access Management (IAM) solutions are designed to accommodate evolving business needs while remaining developer-friendly.In essence, the quest for an ideal login experience is neverending, but with the right IAM solution, developers can perform modern application development with confidence and ease.&lt;/p&gt;

&lt;p&gt;Recently, I had a task to implement a solution supporting a self-sign-up process and providing users with limited-time access to applications until they've subscribed for full access. &lt;/p&gt;

&lt;h2&gt;
  
  
  Solution proposed
&lt;/h2&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%2F3xs1cb0g5ok2t51boq97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xs1cb0g5ok2t51boq97.png" alt="Image description" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application redirects users to the Identity Provider (IDP) during the login process (configuration needs to be provided). The IDP will facilitate self-registration, creating a user profile in an external persistent store, such as a MySQL database, with a trial period. Subsequently, an external payment system will alter the user's status in the database upon successful payment confirmation.&lt;/p&gt;

&lt;p&gt;During the login flow, upon successful user identification, the application will verify the user's status in the external database. If the user attempts to log in during the trial period, access will be granted. However, if the user tries to log in after the trial period and payment confirmation is pending, access will be denied. &lt;/p&gt;

&lt;p&gt;The WSO2 &lt;a href="https://wso2.com/asgardeo/"&gt;Asgardeo&lt;/a&gt; is used as IDP and &lt;a href="https://choreo.dev/"&gt;Choreo&lt;/a&gt; as an Integration platform.&lt;/p&gt;




&lt;h2&gt;
  
  
  Database setup
&lt;/h2&gt;

&lt;p&gt;I have used the publicly available MySQL database and created a simple table with the following DDL.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CREATE DATABASE&lt;/code&gt;cloud_demo&lt;code&gt;;&lt;br&gt;
CREATE TABLE&lt;/code&gt;Users&lt;code&gt;(&lt;br&gt;
&lt;/code&gt;id&lt;code&gt;int NOT NULL AUTO_INCREMENT,&lt;br&gt;
&lt;/code&gt;userName&lt;code&gt;varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,&lt;br&gt;
&lt;/code&gt;allowAccess&lt;code&gt;int NOT NULL,&lt;br&gt;
&lt;/code&gt;endSub&lt;code&gt;date NOT NULL,&lt;br&gt;
  PRIMARY KEY (&lt;/code&gt;id&lt;code&gt;)&lt;br&gt;
) ENGINE=InnoDB AUTO_INCREMENT=56 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  IDP setup
&lt;/h2&gt;

&lt;p&gt;In Asgardeo created an organization YDNC.&lt;br&gt;
In Login&amp;amp;Registation, click on Self Registration and enable it.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn866mvqboyp2hxw0e065.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn866mvqboyp2hxw0e065.png" alt="Image description" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&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%2Fgdu6r7ikzwfgs6srzrkb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgdu6r7ikzwfgs6srzrkb.png" alt="Image description" width="800" height="373"&gt;&lt;/a&gt;&lt;br&gt;
In the Event section check the Registration events.&lt;/p&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%2F8r17irk51zh0h2tpbgzu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8r17irk51zh0h2tpbgzu.png" alt="Image description" width="800" height="243"&gt;&lt;/a&gt;&lt;/p&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%2Fye1momw3asuvz9lwz9az.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fye1momw3asuvz9lwz9az.png" alt="Image description" width="800" height="561"&gt;&lt;/a&gt;&lt;br&gt;
From here if you can click on 'Go to Choreo', note that you need to have a valid subscription and organization with the same name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choreo setup
&lt;/h2&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%2Fc30as1w65noicvevk1fn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc30as1w65noicvevk1fn.png" alt="Image description" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Create a CRUD service and expose it as an API&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;Click on the 'Create' button above Component Listing and choose Service. &lt;/p&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%2Flqs61ro6v24z1h3tvmrj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqs61ro6v24z1h3tvmrj.png" alt="Image description" width="800" height="359"&gt;&lt;/a&gt;&lt;br&gt;
Note that you will need a GitHub repository with your code. I have used  &lt;a href="https://ballerina.io/"&gt;Ballerina&lt;/a&gt;, a cloud-native language optimized for integration.&lt;br&gt;
Creating the REST API service to connect with DB to support the CRUD command is straightforward. &lt;/p&gt;

&lt;p&gt;`service /company on new http:Listener(8090) {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;isolated resource function post user(@http:Payload User payload) returns error? {
    sql:ParameterizedQuery insertQuery = `INSERT INTO Users (userName,allowAccess,endSub) VALUES (${payload.userName}, ${payload.allowAccess}, DATE_ADD(now(),interval 5 day))`;
    sql:ExecutionResult _ = check mysqlClient-&amp;gt;execute(insertQuery);
}

isolated resource function put user(@http:Payload User payload) returns error? {
    sql:ParameterizedQuery updateQuery = `UPDATE  Users SET allowAccess=${payload.allowAccess},
                                         endSub=${payload?.endSub} where
                                         userName= ${payload.userName}`;
    sql:ExecutionResult _ = check mysqlClient-&amp;gt;execute(updateQuery);
}

isolated resource function get users(string userName) returns json|error {
    sql:ParameterizedQuery selectQuery = `select userName,allowAccess,endSub from Users where userName=${userName}`;
    stream &amp;lt;User, sql:Error?&amp;gt; resultStream = mysqlClient-&amp;gt;query(selectQuery);
    User[] users = [];

    check from User item in resultStream
        do {
            users.push(item);
        };
    return users;
}

isolated resource function post risk(@http:Payload RiskRequest payload) returns User|error? {

    sql:ParameterizedQuery selectQuery = `select userName,allowAccess,endSub from Users where userName=${payload.userName}`;

    stream &amp;lt;User, sql:Error?&amp;gt; resultStream =  mysqlClient-&amp;gt;query(selectQuery);
    User[] users = [];

    check from User item in resultStream
        do {
            users.push(item);
        };
    return users[0];
}

isolated resource function delete user(string userName) returns error? {
    sql:ParameterizedQuery deleteQuery = `DELETE FROM Users WHERE userName = ${userName}`;
    sql:ExecutionResult _ = check mysqlClient-&amp;gt;execute(deleteQuery);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}`&lt;/p&gt;

&lt;p&gt;Git-hub repository &lt;a href="https://github.com/lpastor74/db_crud"&gt;https://github.com/lpastor74/db_crud&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once your component is created you can publish it and set up a configuration per environment.&lt;/p&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%2F2x5iodfp4dn4ek8ppcwa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x5iodfp4dn4ek8ppcwa.png" alt="Image description" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;API Service is public and it will be visible in the developer portal.&lt;/p&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%2F9p0m4tpi48ytsursynfm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9p0m4tpi48ytsursynfm.png" alt="Image description" width="362" height="309"&gt;&lt;/a&gt;&lt;/p&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%2Fyura0kgvtmnzy4q9iwk5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyura0kgvtmnzy4q9iwk5.png" alt="Image description" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create an application and subscribe to API. In the credential section note the ClientID, Secret, Token Endpoint, and API service URL because you will need it to finish the setup of the webhook component.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Create a webhook&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;Click on the 'Create' button above Component Listing and choose Webhook. The code to handle the 'add user' event checks if the method is 'SELF_SIGNUP' and connects to API service and in DB creates the record with the user name and sets up the allowAccess value to 0 as forbidden.&lt;/p&gt;

&lt;p&gt;`remote function onAddUser(asgardeo:AddUserEvent event ) returns error? {&lt;br&gt;
      log:printInfo(event.toJsonString());&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  json __user = event.toJson();

  string method  = check __user.eventData.userOnboardMethod;
  if(method=="SELF_SIGNUP")
  { 
       string userNameStr  = check __user.eventData.userName;
       log:printInfo(userNameStr);
       http:Client http_Client = check new (_endUrl, 
         auth = {
                 tokenUrl: _tokenUrl,
                 clientId: _clientId,
                 clientSecret: _clientSecret
         });
         log:printInfo("...sending...");
         anydata|http:ClientError unionResult = check http_Client-&amp;gt;/user.post({
             userName: userNameStr,
             allowAccess: 0
         });
  }    
}`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Git-hub repository &lt;a href="https://github.com/lpastor74/asgrd-hook"&gt;https://github.com/lpastor74/asgrd-hook&lt;/a&gt;&lt;br&gt;
Once your component is created you can publish them and set a configuration per environment.&lt;/p&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%2Ffy4u075f08m2q79ads8f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffy4u075f08m2q79ads8f.png" alt="Image description" width="800" height="374"&gt;&lt;/a&gt;&lt;br&gt;
Note that the configuration of the webhook is populated automatically and you are only responsible for filling up the configuration to allow connecting to your REST API created in the previous section&lt;/p&gt;

&lt;h2&gt;
  
  
  Create an application in IDP
&lt;/h2&gt;

&lt;p&gt;I chose a single-page application and the Sample React application provided in the QuickStart tab to run it locally, to simulate the login flow.&lt;br&gt;
Don't forget to update the app with your configuration (ClientID, Base URL, Redirect URL, and Scope). All details are in the Quickstart section. &lt;/p&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%2Fy6ux0cgchna5ckm7kd87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy6ux0cgchna5ckm7kd87.png" alt="Image description" width="800" height="638"&gt;&lt;/a&gt;&lt;/p&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%2Fmvhoy8cfxeql4ote7n5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvhoy8cfxeql4ote7n5l.png" alt="Image description" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;in Login Flow enable Conditional Authentication and put the following code&lt;/p&gt;

&lt;p&gt;`var errorPageParameters = {&lt;br&gt;
    'status': 'Unauthorized',&lt;br&gt;
    'statusMsg': 'You need have valid subsription.'&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;var errorPage = '';&lt;/p&gt;

&lt;p&gt;var onLoginRequest = function(context) {&lt;br&gt;
    executeStep(1, {&lt;br&gt;
        onSuccess: function(context) {&lt;br&gt;
            var today = new Date();&lt;br&gt;
            var user = context.currentKnownSubject;&lt;br&gt;
            Log.debug('UserName of ' + context.currentKnownSubject.uniqueId + ' is : ' + user.username);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        var connectionMetadata = {
            "url": "https://URLtoPublicAPIservice/risk",
            "consumerKey": "xxxxxx",
            "consumerSecret": "xxxxx",
            "asgardeoTokenEndpoint": "https://api.asgardeo.io/t/ydnc/oauth2/token"
        };

        var requestPayload = {
            "userName": user.username
        };

        callChoreo(connectionMetadata, requestPayload, {
            onSuccess: function(context, data) {
                Log.info("Successfully invoked the Choreo API.");
                Log.info(data.userName);
                Log.info(data.allowAccess);

                if (data.allowAccess == 0) and (today &amp;gt; data.endSub){
                    Log.debug('User ' + context.currentKnownSubject.uniqueId + ' dont have valid subscription.');
                    sendError(errorPage, errorPageParameters);
                }

            },
            onFail: function(context, data) {
                Log.info("Error occurred while invoking the Choreo API.");
                Log.info(data);
            },
            onTimeout: function(context, data) {
                Log.info("Invoking Choreo API timed out.");
                Log.info(data);
            }
        });
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;};` &lt;/p&gt;




&lt;h2&gt;
  
  
  Test everything
&lt;/h2&gt;

&lt;p&gt;Locally, start the React application on &lt;a href="https://localhost:3000"&gt;https://localhost:3000&lt;/a&gt;&lt;/p&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%2F2o3g8r4t9lde32ujwotu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2o3g8r4t9lde32ujwotu.png" alt="Image description" width="800" height="515"&gt;&lt;/a&gt;&lt;br&gt;
On login, the user will be redirected to Asgardeo and SignIn form (please, observe I branded the form ;)) will have the option to Register.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foncdlqxbyknoa1w75bli.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foncdlqxbyknoa1w75bli.png" alt="Image description" width="800" height="375"&gt;&lt;/a&gt;&lt;br&gt;
The user will populate the required field, and if he wants, some of the optional ones.  &lt;/p&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%2Fmboyx8jmzbzma6wko7oq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmboyx8jmzbzma6wko7oq.png" alt="Image description" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&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%2F2318t1qy34uly57lws5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2318t1qy34uly57lws5e.png" alt="Image description" width="800" height="752"&gt;&lt;/a&gt;&lt;br&gt;
Upon successful account creation, we can observe runtime logs in Choreo indicating that the event was triggered.&lt;/p&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%2Fufuxuvegx4iox3j1ok50.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufuxuvegx4iox3j1ok50.png" alt="Image description" width="800" height="321"&gt;&lt;/a&gt;&lt;br&gt;
And in DB we have a new record with the user email, status 0, and endSub date set 5 days in the future.&lt;/p&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%2Faeg9kf2j0or46a3k5idh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faeg9kf2j0or46a3k5idh.png" alt="Image description" width="800" height="338"&gt;&lt;/a&gt;&lt;br&gt;
If the user tries to access during these 5 days login will be successful but after that (if the status is not set to 1) he will get the following message.&lt;/p&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%2Fv7le4wq7ctneep0l6sih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7le4wq7ctneep0l6sih.png" alt="Image description" width="544" height="658"&gt;&lt;/a&gt;&lt;br&gt;
Note that I have not covered the part where, after valid payment, the user status is changed in DB from 0 to 1.&lt;br&gt;
Integrating with the publicly exposed API will be straightforward. You just need to make a PUT call to the /user method and include the following payload.&lt;br&gt;
&lt;code&gt;{&lt;br&gt;
  "userName": correctUserName,&lt;br&gt;
  "allowAccess": 1&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final note&lt;/strong&gt;&lt;br&gt;
All functionality presented here is available out of the box and with a free subscription.&lt;br&gt;
Good luck and happy coding &lt;/p&gt;

</description>
      <category>ciam</category>
      <category>wso2</category>
      <category>idp</category>
      <category>iam</category>
    </item>
    <item>
      <title>IDP init SAML SSO login flow</title>
      <dc:creator>Laslo Pastor</dc:creator>
      <pubDate>Tue, 07 Nov 2023 03:40:43 +0000</pubDate>
      <link>https://dev.to/lpastor74/idp-init-saml-sso-login-flow-3jl1</link>
      <guid>https://dev.to/lpastor74/idp-init-saml-sso-login-flow-3jl1</guid>
      <description>&lt;p&gt;This article covers the initiation of the Identity Provider (IDP) over Security Assertion Markup Language (SAML) Single-Sign-On (SSO) login flow, serving as a quick setup guide. If you have any comments or suggestions, please feel free to reach out to me.&lt;/p&gt;

&lt;p&gt;Use case:&lt;br&gt;
Is IDP init right for my organization?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simplifies experience by requiring an identification process before accessing any Service Providers (SPs).&lt;/li&gt;
&lt;li&gt;Ensures a consistent user experience across various channels and services.&lt;/li&gt;
&lt;li&gt;Establishes a centralized hub for maintaining a consistent level of security across all resources, incorporating Multi-Factor Authentication (MFA), biometric verification, or adaptive login.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will try to explain possible scenarios with Azure Microsoft Entra ID (AEID) and &lt;a href="https://wso2.com/identity-server/"&gt;WSO2 IS platform&lt;/a&gt;.&lt;br&gt;
Both can be used for free. Microsoft Entra ID has a free tier and WSO2 is open source and the version downloaded from the site can be used free for preproduction env.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup WSO2 IS
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Download it, unzip it, setup JAVA_HOME, run it.
(a good place to start is &lt;a&gt;WSO2 IS documentation&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note: WSO2 IS version 7 will be released by the end of Nov 2023. The full B2B concept will be implemented as a first-class citizen functionality. This concept started first in the WSO2 SaaS platform [Asgardeo].(&lt;a href="https://wso2.com/asgardeo/"&gt;https://wso2.com/asgardeo/&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;After logging in to IS, you will be at the root organization level.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;go to &lt;strong&gt;&lt;a href="https://localhost:9443/console"&gt;https://localhost:9443/console&lt;/a&gt;&lt;/strong&gt; (if you haven't changed anything in /repository/conf/deployment.toml file the platform should run on the default 9443 port) and log in with admin/admin (username/password)&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;Create the organizational structure 
(ORG_A, ORG_B,ORG_C,ORG_D)&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;Create an application at the root level in my case with the following settings&lt;/li&gt;
&lt;/ol&gt;

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

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

&lt;p&gt;name : Simple SAML app&lt;/p&gt;

&lt;p&gt;Issuer: simple_saml_app&lt;/p&gt;

&lt;p&gt;Assertion consumer service URLs:&lt;br&gt;
&lt;a href="http://localhost.com:8080/saml2-web-app-pickup-manager.com/home.jsp"&gt;http://localhost.com:8080/saml2-web-app-pickup-manager.com/home.jsp&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Note: Issuer is used to uniquely identify your service/application, while Assertion consumer service URLs is URL where your application will receive SAML assertion from IDP. In my case, I'm using the demo application found on &lt;a href="https://is.docs.wso2.com/en/latest/guides/login/cross-protocol-logout/#deploy-the-samples"&gt;WSO2 Samples page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, shared the application with ORG_D.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;strong&gt;You need to check it the 'Enable IdP initiated SSO' in the Protocol tab.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Azure
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to Azure/MS Entra ID/Enterprise application/ and create a new one by clicking on the 'Create your own application' button. In my case, I named it &lt;strong&gt;IDPInit&lt;/strong&gt;. Choose 'Single sign-on from the left menu and choose SAML application.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Edit Basic SAML Configuration with the following:&lt;/p&gt;

&lt;p&gt;Identifier: IDPInit&lt;/p&gt;

&lt;p&gt;Reply URL (Assertion Consumer Service URL):&lt;br&gt;
&lt;a href="https://localhost:9443/samlsso?spEntityID=simple_saml_app&amp;amp;fidp=OrganizationSSO&amp;amp;org=ORG_D"&gt;https://localhost:9443/samlsso?spEntityID=simple_saml_app&amp;amp;fidp=OrganizationSSO&amp;amp;org=ORG_D&lt;/a&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Note: If you want to change from the SAML application and redirect login flow to the OIDC application the Reply URL should look like this:&lt;br&gt;
Reply URL (Assertion Consumer Service URL):&lt;br&gt;
&lt;a href="https://localhost:9443/oauth2/authorize?client_id=%5Boidc_app_client_id%5D&amp;amp;fidp=OrganizationSSO&amp;amp;org=ORG_C&amp;amp;redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fpickup-manager%2Foauth2client&amp;amp;response_type=id_token&amp;amp;scope=openid"&gt;https://localhost:9443/oauth2/authorize?client_id=[oidc_app_client_id]&amp;amp;fidp=OrganizationSSO&amp;amp;org=ORG_C&amp;amp;redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fpickup-manager%2Foauth2client&amp;amp;response_type=id_token&amp;amp;scope=openid&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Download the Certificate (Base64) and Federation MetadataXML and save it (you will need later)&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Go back to WSO2 IS
&lt;/h2&gt;

&lt;p&gt;Switch to sub-Organization D and create a new Standard based connection with SAML protocol.&lt;br&gt;
name: IDPInit (same as we defined in Azure)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---NX_dcah--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4f4vhmuz5yghh986kqdz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---NX_dcah--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4f4vhmuz5yghh986kqdz.png" alt="Image description" width="800" height="914"&gt;&lt;/a&gt;&lt;br&gt;
Service provider entity ID: IDPInit&lt;br&gt;
Upload the XML metadata we downloaded from Azure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WwUGcFdX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iwt56518ldk917on3hv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WwUGcFdX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iwt56518ldk917on3hv0.png" alt="Image description" width="800" height="918"&gt;&lt;/a&gt;&lt;br&gt;
Upload the downloaded certificate. &lt;/p&gt;

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

&lt;p&gt;Go to the application, and choose the Simple SAML app.&lt;br&gt;
In Sign-in Method and in Classic Editor choose 'Start with Default configuration'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HyE-HwsB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ptq99q9wlanacd32l0o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HyE-HwsB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ptq99q9wlanacd32l0o.png" alt="Image description" width="800" height="829"&gt;&lt;/a&gt;&lt;br&gt;
Remove 'Username and password; and add 'IDPInit' Authentication connector&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Back to Azure Again
&lt;/h2&gt;

&lt;p&gt;Assign a user(s) that should have the right to log in with the IDPInit application.&lt;/p&gt;

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

&lt;p&gt;while you are there note the attributes and claims that will be passed in SAML accertion.&lt;/p&gt;

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

&lt;p&gt;In the Properties section, you will find the &lt;strong&gt;User access URL&lt;/strong&gt; link that can be used to initiate the flow. This is the link that your application will redirect the user to start the login flow.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Claims mapping
&lt;/h2&gt;

&lt;p&gt;When you finish the login flow, the following popup will indicate that the required claim received from SAML assertion is not mapped to the application.&lt;/p&gt;

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

&lt;p&gt;Fill out the claim mapping in the WSO2 'IDPInit' Authentication connector &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--givdQwnp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z9ppewl90y82pzy4l5zl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--givdQwnp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z9ppewl90y82pzy4l5zl.png" alt="Claim mapping in wso2 connector" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The correct values for External IdP Attribute can be found on Azure in &lt;strong&gt;Attributes &amp;amp; Claims&lt;/strong&gt; section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U1XICGj3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kk13ejf31nwaiuv5zqvh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U1XICGj3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kk13ejf31nwaiuv5zqvh.png" alt="Attributes &amp;amp; Claims section in Azure" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Good luck!&lt;/p&gt;

</description>
      <category>wso2</category>
      <category>idp</category>
      <category>sso</category>
      <category>saml</category>
    </item>
  </channel>
</rss>
