Wednesday, January 25, 2023

Configuring a Distributed API Manager Deployment with Gateway and Control Plane

In the distributed setup, the API-M server profiles are deployed as separate API-M nodes. Followings are the APIM nodes you can have in a distributed deployment support for our pattern.

  • Gateway Worker Node - API-M nodes running the Gateway profile.
  • Control Plane Node - API-M nodes running the Control Plane profile. The Control Plane includes the Traffic Manager, Key Manager, Publisher, and Developer Portal components.


1. Install WSO2 API Manager

  • Download the WSO2 API Manager.
  • Create copies of the API-M distribution for the individual profiles

2. Install and configure the databases

You can create the required databases for the API-M deployment in a separate server and point to the databases from the respective nodes.

Below are the default databases which will be used within API Manager.
  • WSO2AM_DB - WSO2 API Manager has this database keeping its specific API-M related data.
  • WSO2SHARED_DB - This database contains the registry and user management data.
  • WSO2CARBON_DB - This database has the internal data related to the product.
Databases used by API-M profiles:

WSO2AM_DBWSO2SHARED_DBWSO2CARBON_DB
Control Plane profileYesYesYes
Gateway profileNoYesYes

It is recommended to use an industry-standard RDBMS such as Oracle, PostgreSQL, MySQL, MS SQL, etc. WSO2 products are shipped with scripts for creating the required tables in all the required databases: The scripts for creating tables for API-M, user management, and registry data are stored in the <API-M_HOME>/dbscripts directory.

In this example i'm using PostgreSQL.

3. Create and import SSL certificates

Create an SSL certificate for each of the WSO2 API-M nodes and import them to the keystore and the truststore. This ensures that hostname mismatch issues in the certificates will not occur.

Note: The same primary keystore should be used for all API Manager instances to decrypt the registry resources.

For more details:


4. Configure and start the profiles

4.1 Configure the Gateway Nodes

Follow these steps to configure the Gateway to communicate with the Control Plane.

Open the <API-M_HOME>/repository/conf/deployment.toml file of the Gateway node.
Add the following configurations to the deployment.toml file.

Note: Update the parameters as necessary.

--------------------------------------------------------------------------------------------------------
[server]
hostname = "{{apim gateway lb host}}"
node_ip = "{{node_ip}}"
server_role = "gateway-worker"
offset= 0

[user_store]
type = "database_unique_id"

[super_admin]
username = "$secret{admin_username}"
password = "$secret{admin_password}"
create_admin_account = true

#Databases

[database.apim_db]
type = "postgre"
url = "jdbc:postgresql://{{db host}}:5432/apim_db"
username = "$secret{wso2am_db_username}"
password = "$secret{wso2am_db_password}"
driver = "org.postgresql.Driver"
validationQuery = "SELECT 1"
pool_options.maxActive = 50
pool_options.maxWait = 30000

[database.shared_db]
type = "postgre"
url = "jdbc:postgresql://{{db host}}:5432/shared_db"
username = "$secret{wso2shared_db_username}"
password = "$secret{wso2shared_db_password}"
driver = "org.postgresql.Driver"
validationQuery = "SELECT 1"
pool_options.maxActive = 50
pool_options.maxWait = 10000
pool_options.validationInterval = 10000

[database.local]
type = "postgre"
url = "jdbc:postgresql://{{db host}}:5432/carbon_db"
username = "$secret{wso2carbon_db_username}"
password = "$secret{wso2carbon_db_password}"
driver = "org.postgresql.Driver"
validationQuery = "SELECT 1"


 # JWT Generation
[apim.jwt]
enable = "true"
encoding = "base64"
generator_impl = "org.wso2.carbon.apimgt.keymgt.token.JWTGenerator"
claim_dialect = "http://wso2.org/claims"
header = "X-JWT-Assertion"
signing_algorithm = "SHA256withRSA"
enable_user_claims = "false"
claims_extractor_impl = "org.wso2.carbon.apimgt.impl.token.ExtendedDefaultClaimsRetriever"

[apim.sync_runtime_artifacts.gateway]
gateway_labels = ["Default"]
artifact_retriever = "DBRetriever"
deployment_retry_duration = 15000
data_retrieval_mode = "sync"
event_waiting_time = 5000


[apim.key_manager]
service_url = "https://{{apim control plane lb host}}/services/"
username = "$ref{super_admin.username}"
password = "$ref{super_admin.password}"

[apim.throttling]
enable_data_publishing = true
enable_policy_deploy = true
enable_blacklist_condition = true
enable_persistence = true
username = "$ref{super_admin.username}"
password = "$ref{super_admin.password}"
service_url = "https://{{apim control plane lb host}}/services/"
throttle_decision_endpoints = ["tcp://{{apim control plane 1 host}}:5672","tcp://{{apim control plane 2 host}}:5672"]
enable_unlimited_tier = true
enable_header_based_throttling = false
enable_jwt_claim_based_throttling = false
enable_query_param_based_throttling = false

[[apim.throttling.url_group]]
traffic_manager_urls = ["tcp://{{apim control plane 1 host}}:9611"]
traffic_manager_auth_urls = ["ssl://{{apim control plane 1 host}}:9711"]

[[apim.throttling.url_group]]
traffic_manager_urls = ["tcp://{{apim control plane 2 host}}:9611"]
traffic_manager_auth_urls = ["ssl://{{apim control plane 2 host}}:9711"]


[transport.http]
properties.port = 9763
properties.proxyPort = 80

[transport.https]
properties.port = 9443
properties.proxyPort = 443

[apim.analytics]
enable = false
auth_token = "auth_token"

# Caches
[apim.cache.gateway_token]
enable = true
expiry_time = 15

[apim.cache.resource]
enable = true

[apim.cache.jwt_claim]
enable = true
expiry_time = 900

[apim.oauth_config]
enable_outbound_auth_header = true
auth_header = "Authorization"

[apim.cors]
allow_origins = "*"
allow_methods = ["GET","PUT","POST","DELETE","PATCH","OPTIONS"]
allow_headers = ["authorization","Access-Control-Allow-Origin","Content-Type","SOAPAction"]
allow_credentials = false


[oauth.grant_type.token_exchange]
enable = true
allow_refresh_tokens = true
iat_validity_period = "1h"

# Condition check for whether the Certification Import Option is enabled
[keystore.primary]
file_name = "primary.pfx"
password = "$secret{primaryKeyStorePassword}"
alias = "wso2carbon"
key_password = "$secret{primaryKeyPassword}"
type = "PKCS12"

[keystore.internal]
file_name = "internal.pfx"
password = "$secret{internalKeyStorePassword}"
alias = "wso2carbon"
key_password = "$secret{internalKeyPassword}"
type = "PKCS12"

[keystore.tls]
file_name = "tls.pfx"
password = "$secret{tlsKeyStorePassword}"
alias = "wso2carbon"
key_password = "$secret{tlsKeyPassword}"
type = "PKCS12"


[truststore]
file_name = "client-truststore.jks"
password = "$secret{truststrorePassword}"
alias = "symmetric.key.value"
algorithm = "AES"

[secrets]
admin_username = "[{{ admin_username }}]"
admin_password = "[{{ admin_password }}]"
wso2am_db_username = "[{{ wso2am_db_username }}]"
wso2am_db_password = "[{{ wso2am_db_password }}]"
wso2shared_db_username = "[{{ wso2shared_db_username }}]"
wso2shared_db_password = "[{{ wso2shared_db_password }}]"
wso2carbon_db_username = "[{{ wso2carbon_db_username }}]"
wso2carbon_db_password = "[{{ wso2carbon_db_password }}]"
truststrorePassword = "[{{truststore.storePassword}}]"

primaryKeyStorePassword  = "[{{primary.privateKeyPasssword}}]"
primaryKeyPassword  = "[{{primary.privateKeyPasssword}}]"
internalKeyStorePassword  = "[{{internal.privateKeyPasssword}}]"
internalKeyPassword  = "[{{internal.privateKeyPasssword}}]"
tlsKeyStorePassword  = "[{{tls.privateKeyPasssword}}]"
tlsKeyPassword  = "[{{tls.privateKeyPasssword}}]"

---------------------------------------------------------------------------------------------------------

4.2 Configure the Control Plane Nodes

Follow these steps to configure the Control Plane to communicate with the Gateway.

Open the <API-M_HOME>/repository/conf/deployment.toml file of the Gateway node.
Add the following configurations to the deployment.toml file.

Note: Update the parameters as necessary.

------------------------------------------------------------------------------------------------------------

[server]
hostname = "{{apim control plane lb host}}"
node_ip = "{{node_ip}}"
server_role = "control-plane"
base_path = "${carbon.protocol}://${carbon.host}:${carbon.management.port}"

[user_store]
type = "database_unique_id"

[super_admin]
username = "$secret{admin_username}"
password = "$secret{admin_password}"
create_admin_account = true

#Databases

[database.apim_db]
type = "postgre"
url = "jdbc:postgresql://{{db host}}:5432/apim_db"
username = "$secret{wso2am_db_username}"
password = "$secret{wso2am_db_password}"
driver = "org.postgresql.Driver"
validationQuery = "SELECT 1"
pool_options.maxActive = 50
pool_options.maxWait = 30000

[database.shared_db]
type = "postgre"
url = "jdbc:postgresql://{{db host}}:5432/shared_db"
username = "$secret{wso2shared_db_username}"
password = "$secret{wso2shared_db_password}"
driver = "org.postgresql.Driver"
validationQuery = "SELECT 1"
pool_options.maxActive = 50
pool_options.maxWait = 10000
pool_options.validationInterval = 10000

[database.local]
type = "postgre"
url = "jdbc:postgresql://{{db host}}:5432/carbon_db"
username = "$secret{wso2carbon_db_username}"
password = "$secret{wso2carbon_db_password}"
driver = "org.postgresql.Driver"
validationQuery = "SELECT 1"

[tenant_mgt]
enable_email_domain = true

[apim.devportal]
url = "https://{{apim control plane lb host}}/devportal"

[transport.http]
properties.port = 9763
properties.proxyPort = 80

[transport.https]
properties.port = 9443
properties.proxyPort = 443

 # JWT Generation
[apim.jwt]
enable = "true"
encoding = "base64"
generator_impl = "org.wso2.carbon.apimgt.keymgt.token.JWTGenerator"
claim_dialect = "http://wso2.org/claims"
header = "X-JWT-Assertion"
signing_algorithm = "SHA256withRSA"
enable_user_claims = "false"
claims_extractor_impl = "org.wso2.carbon.apimgt.impl.token.ExtendedDefaultClaimsRetriever"

[apim.sync_runtime_artifacts.publisher]
artifact_saver = "DBSaver"
publish_directly_to_gateway = "false"


[[apim.gateway.environment]]
name = "Default"
type = "hybrid"
display_in_api_console = true
description = "This is a hybrid gateway that handles both production and sandbox token traffic."
show_as_token_endpoint_url = true
service_url = "https://{{apim gateway lb host}}/services/"
ws_endpoint = "ws://{{apim gateway lb host}}:9099"
wss_endpoint = "wss://{{apim gateway lb host}}:8099"
http_endpoint = "http://{{apim gateway lb host}}"
https_endpoint = "https://{{apim gateway lb host}}"
username= "${admin.username}"
password= "${admin.password}"
websub_event_receiver_http_endpoint = "http://{{apim gateway lb host}}:9021"
websub_event_receiver_https_endpoint = "https://{{apim gateway lb host}}:8021"
# provider = "wso2"

# Event Hub configurations
[apim.event_hub]
enable = true
username= "$ref{super_admin.username}"
password= "$ref{super_admin.password}"
service_url = "https://{{apim control plane lb host}}/services/"
event_listening_endpoints = ["tcp://{{apim control plane 1 host}}:5672"]
event_duplicate_url = ["tcp://{{apim control plane 2 host}}:5672"]

[[apim.event_hub.publish.url_group]]
urls = ["tcp://{{apim control plane 1 host}}:9611"]
auth_urls = ["ssl://{{apim control plane 1 host}}:9711"]

[[apim.event_hub.publish.url_group]]
urls = ["tcp://{{apim control plane 2 host}}:9611"]
auth_urls = ["ssl://{{apim control plane 2 host}}:9711"]

# key manager implementation
[apim.key_manager]
service_url = "https://{{apim control plane lb host}}/services/"

[apim.analytics]
enable = false
auth_token = "auth_token"

[apim.cache_invalidation]
enabled = true
domain = "control-plane-domain"

# Caches
[apim.cache.gateway_token]
enable = true
expiry_time = 15

[apim.cache.resource]
enable = true

[apim.cache.jwt_claim]
enable = true
expiry_time = 900

[apim.oauth_config]
enable_outbound_auth_header = true
auth_header = "Authorization"

[apim.cors]
allow_origins = "*"
allow_methods = ["GET","PUT","POST","DELETE","PATCH","OPTIONS"]
allow_headers = ["authorization","Access-Control-Allow-Origin","Content-Type","SOAPAction"]
allow_credentials = false


[[event_listener]]
id = "token_revocation"
type = "org.wso2.carbon.identity.core.handler.AbstractIdentityHandler"
name = "org.wso2.is.notification.ApimOauthEventInterceptor"
order = 1

[event_listener.properties]
notification_endpoint = "https://{{apim control plane lb host}}/internal/data/v1/notify"
username = "${super_admin.username}"
password = "${super_admin.password}"
'header.X-WSO2-KEY-MANAGER' = "default"

[oauth.grant_type.token_exchange]
enable = true
allow_refresh_tokens = true
iat_validity_period = "1h"


# Condition check for whether the Certification Import Option is enabled
[keystore.primary]
file_name = "primary.pfx"
password = "$secret{primaryKeyStorePassword}"
alias = "wso2carbon"
key_password = "$secret{primaryKeyPassword}"
type = "PKCS12"

[keystore.internal]
file_name = "internal.pfx"
password = "$secret{internalKeyStorePassword}"
alias = "wso2carbon"
key_password = "$secret{internalKeyPassword}"
type = "PKCS12"

[keystore.tls]
file_name = "tls.pfx"
password = "$secret{tlsKeyStorePassword}"
alias = "wso2carbon"
key_password = "$secret{tlsKeyPassword}"
type = "PKCS12"

[truststore]
file_name = "client-truststore.jks"
password = "$secret{truststrorePassword}"
alias = "symmetric.key.value"
algorithm = "AES"

[secrets]
admin_username = "[{{ admin_username }}]"
admin_password = "[{{ admin_password }}]"
wso2am_db_username = "[{{ wso2am_db_username }}]"
wso2am_db_password = "[{{ wso2am_db_password }}]"
wso2shared_db_username = "[{{ wso2shared_db_username }}]"
wso2shared_db_password = "[{{ wso2shared_db_password }}]"
wso2carbon_db_username = "[{{ wso2carbon_db_username }}]"
wso2carbon_db_password = "[{{ wso2carbon_db_password }}]"
truststrorePassword = "[{{truststore.storePassword}}]"

primaryKeyStorePassword  = "[{{primary.privateKeyPasssword}}]"
primaryKeyPassword  = "[{{primary.privateKeyPasssword}}]"
internalKeyStorePassword  = "[{{internal.privateKeyPasssword}}]"
internalKeyPassword  = "[{{internal.privateKeyPasssword}}]"
tlsKeyStorePassword  = "[{{tls.privateKeyPasssword}}]"
tlsKeyPassword  = "[{{tls.privateKeyPasssword}}]"

-----------------------------------------------------------------------------------------------------


Open the server's /etc/hosts file and map the hostnames to IPs.

Format: 
<GATEWAY-LB-IP> gw.wso2.com
<GATEWAY-1-IP> gw-1.wso2.com
<GATEWAY-2-IP> gw-2.wso2.com
<CONTROL-PLANE-LB-IP> cp.wso2.com
<CONTROL-PLANE-1-IP> cp-1.wso2.com
<CONTROL-PLANE-2-IP> cp-2.wso2.com


4.3 Configure carbon.xml

Configure carbon.xml file if you using custom keystores as below.

<Security>
        <!--
            KeyStore which will be used for encrypting/decrypting passwords
            and other sensitive information.
        -->
        <KeyStore>
            <!-- Keystore file location-->
            <Location>${carbon.home}/repository/resources/security/primary.pfx</Location>
            <!-- Keystore type (JKS/PKCS12 etc.)-->
            <Type>PKCS12</Type>
            <!-- Keystore password-->
            <Password>$secret{primaryKeyStorePassword}</Password>
            <!-- Private Key alias-->
            <KeyAlias>wso2carbon</KeyAlias>
            <!-- Private Key password-->
            <KeyPassword>$secret{primaryKeyPassword}</KeyPassword>
        </KeyStore>

        <!--
            The KeyStore which is used for encrypting/decrypting internal data.
            This block is read by Carbon Crypto Service.
        -->
        <InternalKeyStore>
            <!-- Keystore file location-->
            <Location>${carbon.home}/repository/resources/security/internal.pfx</Location>
            <!-- Keystore type (JKS/PKCS12 etc.)-->
            <Type>PKCS12</Type>
            <!-- Keystore password-->
            <Password>$secret{internalKeyStorePassword}</Password>
            <!-- Private Key alias-->
            <KeyAlias>wso2carbon</KeyAlias>
            <!-- Private Key password-->
            <KeyPassword>$secret{internalKeyPassword}</KeyPassword>
        </InternalKeyStore>

        <UserStorePasswordEncryption>InternalKeyStore</UserStorePasswordEncryption>

        <!--
            System wide trust-store which is used to maintain the certificates of all
            the trusted parties.
        -->
        <TrustStore>
            <!-- trust-store file location -->
            <Location>${carbon.home}/repository/resources/security/client-truststore.jks</Location>
            <!-- trust-store type (JKS/PKCS12 etc.) -->
            <Type>JKS</Type>
            <!-- trust-store password -->
            <Password>$secret{truststrorePassword}</Password>
        </TrustStore>



<Security>

4.4 Configure load balancers

You need to properly configure load balancers fronting the two Control Plane nodes and two Gateway nodes.


4.5 Start the API-M nodes

Before starts the servers,

Execute the control plane optimization:
cd <API-M_HOME>/bin/
sh profileSetup.sh -Dprofile=control-plane

Execute the gateway optimization:
cd <API-M_HOME>/bin/
sh profileSetup.sh -Dprofile=gateway-worker

Once you have successfully configured all the API-M nodes in the deployment, you can start the servers.

Starting the Gateway nodes

Open a terminal, navigate to the <API-M-GATEWAY-HOME>/bin folder, and execute the following command

cd <API-M_HOME>/bin/
sh api-manager.sh -Dprofile=gateway-worker

Start the Control Plane nodes

Open a terminal, navigate to the <API-M-CONTROL-PLANE-HOME>/bin folder, and execute the following command:
cd <API-M_HOME>/bin/
sh api-manager.sh -Dprofile=control-plane


5. Sample APIM deployment architecture in Azure cloud.

This is the sample architecture of the APIM deployment in Azure using Azure VMs, Azure scaleset, Azure Load-balancer and Azure Active Directory.




Monday, January 2, 2023

How to Integrate Azure AD for API Authentication in WSO2 APIM

Here I'm covering how to configure WSO2 API Manager 4.1.0 federated authentication with Azure Active Directory step by step(OpenID connect SSO flow)

1. Azure configuration.

1.1 Azure App Registration.

First login to your Azure portal with your credentials. If you don't have an account you can create a free trial account to check this scenario.

Once you successfully logged-in you can see as below.

Click on the Azure Active Directory and select which AD you want to use. If you don't have created AD then you can create a new one for this by clicking on the Create Directory icon. Enter the required details and create new one. It will take few minuted to create an AD for you.

Once all done with new creation select the Azure AD and select App registration on the left navigation panel to register an Open ID client.

Click on the New registration and enter the following details:

  • Name: wso2-apim (any desired name as you want)
  • Supported Account Types: Accounts in this organizational directory only
  • Redirect URI: Web , https://<hostname>:9443/commonauth (change the hostname according to your environment)

And click on Register.

After successful creation you will be redirected to a general info page of the registered application. On this page copy and save the Application (client) ID as it will need for API Manager configurations.


Then click on the Certificates & secrets section in the left side panel and select the New client secret to generate a secret for our newly created wso2-apim application. 

Enter the following details and click Add. 

  • Description: WSO2APIMDEV OIDC Secret (You can change this as per your choice)
  • Expires: Select your desired time period


Then click on Add.
Copy and save the generated client secret value.

After that click on the API permissions in the left navigation panel to configure the OpenID and Profile scope permissions to your application.


Click on the Add a permission button to add new permissions. Once you click, you will see a side window popped up with the following options.


Choose the Microsoft Graph option and select Delegated permissions on the following screen. Then select the following permissions. 

  • email 
  • openid 
  • Profile 


Click on Add permissions. Leave the existing permissions as it is. Then you can see the all configured API permissions as below.



1.2 Group Registration.

Since we are configuring the SSO flow with Azure AD, we will be creating a security group called Subscriber to represent the subscriber role in the Azure service. For Publisher and Creator roles you need to create separate groups respectively. 

Note: You can create Roles in the azure service and assign them to Users. In addition, you can also create Groups in Azure AD and assign it to your Users. 

Click on the Groups on your AD and there click on New group button. Then you will see it as below. Fill the followings in there. 
  • Group type: Security 
  • Group name: Subscriber 
  • Group description: Group for subscriber

Click on the No owners selected. On the prompted side window, select on owner's Azure accounts you need to add. 
Then click on the No members selected. As above step selects desired members you want to add. 
And finally click on Create. You can see the newly created group as below.



Take a note of the Object id value. 

Note: This is to map the Groups with the API Manager’s internal roles. We will be using the Object IDs of the groups to map the roles in the API Manager. 

Create Another Groups for Publisher and Creator as well. 

1.2.1 Add Groups claim.

Now we have to configure our Azure application to populate the Groups claim in the ID token. Go to the Azure application (wso2-apim) and click on Token configurations.


Click on the Add group claim and tick the security groups. Then expand the ID and choose the Group ID and enable Emit groups as role claims and click on Add.


Now all the set with the Azure configurations. But before moving forward, we will make a note on the Authorization and Token endpoints of our Azure application. We will need these endpoints when configuring an Identity provider in the API Manager.



Go to the Overview page of the Azure application and click on the Endpoints button as above. This will pop a side-window with all the necessary endpoints of our application. Make a note on the Authorization v2 and Token v2 endpoints. In addition to the above-set, also make a note on the OpenID Connect metadata document endpoint.

If you go to the endpoint URL mentioned in the OpenID Connect metadata document, you will find a set of metadata to configure an Identity Provider in the API Manager.



2. WSO2 API Manager configuration.

First of all you need to enable "enable_email_domain" property in the API Manager. Reason behind it "preferred_username" claim in Azure ID token represented with email username. So we will be enabling email username in our API Manager server to provision and log-in to the Store nodes.

Go to <apim-home>/repository/conf and open deployment.toml file and add the following entry.

[tenant_mgt] enable_email_domain= true
Add the following entry for the email regex validation since the default validation only checks the 30 characters. [user_store] username_java_regex = '^[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}'

2.1 Identity Provider Creation.

Go to the Carbon Management console, and log-in with the admin credentials.


Select the Add under the Identity Providers and input the followings: 

  • Identity Provide Name: AzureADIDP 
  • Display Name: Azure AD IDP 
  • Choose IDP Certificate Type: Use IDP JWKS Endpoint 
  • Identity Provider’s JWKS Endpoint: the JWKS URI found in the OpenID Connect metadata document 



Next, expand the Claim Configurations > Basic Claim configuration > Define Custom Claim Dialect > Add Claim Mapping and add the following mappings 

  • preferred_username : http://wso2.org/claims/displayName 
  • roles : http://wso2.org/claims/role 
and 
  • User ID Claim URI: preferred_username 
  • Role Claim URI: roles 


Expand the Role configurations and click on the Add Role Mapping. Paste the Object ID acquired from the Subscriber group in the Azure service and map it with our internal subscriber role

  • The Object ID of Subscriber Group : Internal/subscriber

Given below is a sample Role mapping configuration.


Update these for all other groups as well like below.


Then, expand the Federated Authenticators > OAuth2/OpenID Connect Configurations and perform the following

  • Enable OAuth2 / OpenID Connect: true
  • Default: true
  • Client ID: the Client ID of our WSO2APIM Azure app
  • Client Secret: the generated secret of our WSO2APIM Azure app
  • Authorization Endpoint URL: the authorization_endpoint in the OpenID Connect metadata document
  • Token Endpoint URL: the token_endpoint in the OpenID Connect metadata document
  • Userinfo Endpoint URL: the userinfo_endpoint in the OpenID Connect metadata document
  • Additional Query Parameters: scope=openid profile email


And finally, expand the Just-In-Time Provisioning accordion and configure as follows.


And finally click on Register.


2.2 Service Provider Creation.

From API Manager 4.x onwards, both Publisher and Devportal nodes are configured with OIDC SSO flows as default. 

Hence, go to both Publisher and Devportal nodes and click on the Sign-in button to automatically create and register a Service Provider for the OIDC SSO flow. You don't have to log-in to the portals, the above-mentioned process is to create the respective Service Providers in the API Manager. 

Navigate to the Carbon Management console and sign-in with the Admin credentials. 

Click on List under Service Providers section to list the automatically created Service Providers respective to Publisher: apim_publisher and Devportal: apim_devportal.


Click the Edit of the apim_devportal and expand the Claim Configurations. Select "Define Custom Claim Dialect" and make the following changes 

  • preferred_username : http://wso2.org/claims/displayName : Requested 


Next, expand the Local & Outbound Authentication Configuration and select the AzureADIDP as the Federated Authentication and make the following changes


Do the same configurations for apim_publisher. 

Now we are done with all configs. We have now successfully configured OpenID Connect Federated Authentication between Azure AD and Single Sign-On with OpenID Connect with APIM Devportal and Publisher. 

Go to the Publisher or devporal and click on Sign-In. You will be redirected to the Microsoft’s login page to enter the credentials. Enter the credentials of our Microsoft User and then allow the attributes on the consent screen to continue with the federation and provision of the users to the WSO2