Social Account Linking with WSO2 Identity Server

Janak Amarasena
Identity Beyond Borders
11 min readMay 17, 2020

--

How to link a users’ social media account with an already registered local user account of your application. And always retrieve the local user attributes to the application, even when the user login from a social account.

When we onboard users through Just-In-Time(JIT) provisioning we can provision a local user for the federated user and the federated user will be associated with the provisioned local user. But what if we want to associate a federated user to an already existing local user, how can we do this?

We can achieve this by leveraging the adaptive authentication scripting capabilities of the Identity Server.

Scenario 1

I have an application that is used by an existing user who has registered specifically for my application. When the user logs-in to the application using a social media account, I want to link the user's social account with the already registered account. So that when the user logs-in using that social media account still the application will receive the user attributes from user account registered directly with the application (let’s call this the local user account).

Scenario 2

I have an application that is used by an existing user who has registered specifically for my application. Using the applications’ user profile management, I want to let a user link the users’ social media login accounts to the users’ registered local account. So that when the user logs-in using that social media account still the application will receive the user attributes from the user account registered directly with the application.

How to do it

I will be using an Identity Server 5.10.0 distribution for this.

Configuring the Identity Provider

First things first. For both scenarios, we are going to need our Social Identity Provider. Well for this its pretty straight forward. Simply configure an identity provider with a federated authentication. Chances are you have already configured identity providers, and if not refer to this documentation.

Well here's the gist of the configurations I am going to do;

  1. Login to the management console.
  2. Click on Add under Identity Providers in the left side menu.
  3. Add the required details. When adding the Identity Provider Name lets add a name without any spaces. We will be using this name in a URL query parameter for scenario 2 so let's not complicate things by adding spaces.
  4. Configure your preferred social login provider under the Federated Authenticators section.
  5. Click on the Register button at the bottom.

Configuring the Service Provider

I am assuming you already have a Service Provider configured.

Always get the local user attributes

Even when the user login from a social media account, you can get the user account and the attributes of the locally registered user if there is an account association in place.

  1. To do this go to your Service Provider configuration.
  2. Expand the Local & Outbound Authentication Configuration section.
  3. Tick the Assert identity using mapped local subject identifier checkbox and click update a the bottom.

Doing Scenario 1

In simple what we are going to do is use an Identity Provider that will be providing the social login capability and add an adaptive authentication script to your existing Service Provider. That's it.

Setting up the Adaptive Authentication script

Okay now, let’s add the adaptive auth script. Inside your service provider configuration expand the Local & Outbound Authentication Configuration and click on Advanced Configuration under Authentication Type.

  1. Click on Add Authentication Step under Authentication Step Configuration.
  2. Add basic to the Local Authenticators and add the Identity Provider you configured to the Federated Authenticators. (If you have multiple configured IDPs for social login you can add all of them under Federated Authenticators.)

Now in the Script Based Adaptive Authentication add the following script and click Update.

In this script, what basically happens is; we are saying to go through this flow only if the user login with the configured social identity provider(in my case google). Then we are checking if there is already an existing association for this social account and proceeding only if not. Then try to retrieve a local user account in my tenant for a matching email address (in my case the tenant domain is carbon.super). I am looking for a matching email address because when a user has multiple accounts a common link is the users’ email address. You can match the user accounts using multiple claims easily by adding more claims to the claimMap. If a matching local user is found then we link the social account to the local user account.

Trying it out

Add a local user with the same email address you have on the social account that you will be using. Login to your application using the social account. That’s it now the accounts should be associated. To confirm that the association was successful, check “Managing the linked accounts” section at the bottom of this blog.

So in the above, we are doing kind of a silent association. What if you want to make sure the local user account we found is actually belonging to this user? You can prompt the user for authentication for the local user account. Also what if you want to let the user decide whether the user wants to link the accounts? You can prompt the user for consent.

Let's see how you can get that done, For this, you will need to add another step under Authentication Step Configuration in Advanced Configuration. And add basic to the Local Authenticators of the newly added Step.

Now in the Script Based Adaptive Authentication add the following updated script and click Update.

In the script, the additions I have made are, after confirming there is a matching local user account, I prompted the user with this information and asked whether to proceed with the account linking. If the user gave consent then the user is prompted for authentication to confirm the local user account belongs to the user.

<< Tip: I haven’t done this in the script but, after the user has authenticated with basic authentication, you can do additional validation like matching the email addresses or usernames to find out whether the user has actually authenticated using the stored local user account that we found initially, or from another user account, before proceeding to link the two accounts.>>

The page we used to prompt needs to be added to the Identity Server. Create a JSP file called associationConsentForm.jsp as below and add it to the <IS-HOME>/repository/deployment/server/webapps/authenticationendpoint/templates/ directory. You will need to restart the Identity Server for this addition to take effect.

Note that before IS 5.10.0 the init-url.jsp file was located directly inside the authenticationendpoint folder. So if you are using a IS version prior to IS 5.10.0 change the <jsp:directive.include file="../includes/init-url.jsp"/> line to <jsp:directive.include file="../init-url.jsp"/>

You will also need to add this template to the template-mapper.jsp file located at <IS-HOME>/repository/deployment/server/webapps/authenticationendpoint/includes/template-mapper.jsp. Open this file and add the following line;

templateMap.put(“associationConsentForm”,“templates/associationConsentForm.jsp”);

Note that before IS 5.10.0 the template-mapper.jsp file was located directly inside the authenticationendpoint folder. <IS-HOME>/repository/deployment/server/webapps/authenticationendpoint/template-mapper.jsp.

That's it for the configurations. Now when the user login from the social account if there is a matching local account for the email address a consent screen like below will be prompted. If the user clicks “yes” then the user will be prompted to authenticate to the local account. And if the user clicks “no” the user will simply complete authentication with the social account without any linking.

That's it for scenario 1 now let's see how to get scenario 2 done.

Doing Scenario 2

In simple what we are going to do is use an Identity Provider that will be providing the social login capability, add an adaptive authentication script to your existing Service Provider then use a modified authorization code grant request call using the OAuth2 app configure in the Service Provider to trigger the account linking flow. If you seemed confused don’t be, simply read on its actually very simple.

Updating the Service Provider

For this scenario in your Service Provider, we will use an OAuth/OpenID Connect Configuration configured with enabling the authorisation code grant.

<<Best practice: If you're creating the OAuth/OpenID Connect Configuration just for this association flow and you're using a browser-based or mobile application(public client) then make sure NOT to store the client_secret in the application as we have no intention of getting tokens with this. If you're using the OAuth/OpenID Connect Configuration already make sure to use authorization code grant flow with PKCE. However, in my examples, I am not using the PKCE flow just to keep them simple.>>

Since this is a custom flow initiated by the user from a profile page ideally we will have to send the user back to that page. So the Callback Url in the OAuth/OpenID Connect Configuration will be the location of the page where the user started the account linking flow. If you already have a configured Callback URL no worries you can add multiple Callback URLs by using a regex pattern like below for the Callback URL.

regexp=(https://myapp.com/home|https://myapp.com/profile)

Setting up the Adaptive Authentication script

Okay now, let's add the adaptive auth script. Just like in scenario 1, inside your Service Provider configuration expand the Local & Outbound Authentication Configuration and click on Advanced Configuration under Authentication Type. We are going to need 2 steps here.

  1. Click on Add Authentication Step under Authentication Step Configuration twice.
  2. Under Step 1 Add basic to the Local Authenticators.
  3. Under Step 2 add the Identity Provider you configured to the Federated Authenticators. (If you have multiple configured IDPs for social login accounts and you like to make account linking available for all, then add all of them.)

Now in the Script Based Adaptive Authentication add the following script and click Update.

In this script, we are only executing Step 2 if we get an account linking request. Ideally, since the user will be calling this from within the user profile page the user has already authenticated using Step 1 and has an active session within the Identity Server. When the account linking request comes since the user already has an active session Step 2 will be executed and upon successful authentication with the social identity provider, the accounts will be linked. We use the fedIdp param to find out which social identity provider the user is trying to link to.

Trying it out

Like scenario 1, add a local user with the same email address you have on the social account that you will be using. Login to your application using the local user account. Now using the same browser, call the link below.

https://localhost:9443/oauth2/authorize?response_type=code&client_id=<oauth client key>&redirect_uri=<registered callback url>&isLinkRequest=true&fedIdp=<exact Identity Provider Name>Example:
https://localhost:9443/oauth2/authorize?response_type=code&client_id=gtd3LxpJt_9oVIB08ejWdTd4rU0a&redirect_uri=https://myapp.com/profile&isLinkRequest=true&fedIdp=google

Here we are initiating an authorization code grant flow with additional params to engage our account linking flow. If you’re familiar with the authorisation code grant flow, you will notice that this is an ordinary authorization code grant, authorization request with the addition of two parameters isLinkRequest and fedIdp.

isLinkRequest: This parameter should be equal to true. We are using this to mention that this is an account linking request and our flow in the adaptive auth script should be engaged.fedIdp: The name of the Identity Provider the association should be made with. The name should be as stated in the Identity Provider Name of the Identity Provider configuration. Also note this Identity Provider should be available in the federated authenticators configured in Step 2 in Advanced Configuration of the Service Provider previously mentioned.

The idea is, that the user is already logged-in to the application and clicks on the link button on a profile page. Since you already have a session with Identity Server in that browser you will only be prompted to authenticate using your social identity provider stated in the fedIdp param. And once the authentication is complete you will be returned back to the redirect url you sent along with an authorization code. The association flow is complete at this point and you can ignore the received authorisation code.

To confirm that the association was successful, check “Managing the linked accounts” section at the bottom of this blog.

Few more stuff

A complete script for both the scenarios can be found here. Note that for this script there are three authentication steps configured. Step 1 and Step 3 mainly for scenario 1 and Step 2 for scenario 2.

The main functions I have used in the scripts are available from the respective Identity Server GA distributions onwards;

getAssociatedLocalUser - IS 5.9.0
getUniqueUserWithClaimValues - IS 5.9.0
doAssociationWithLocalUser - IS 5.9.0

Managing the linked accounts

How can you check whether the account linking was successful? If you are using Identity Server 5.10.0, for testing purposes the quickest way to check whether the user account linking was successful is to login to the user-portal (https://localhost:9443/user-portal) with the local user account of the test user. In the portal click on Profile Info and scroll a bit down to the External Logins section. If the association was successful the social media account will show up here. You can remove the association from here as well.

So how can you manage the linked account from within your application? From IS 5.10.0 onwards you can use the “User Account Associations” REST API. Look for the APIs with the context /federated-associations. This is the same REST API used by the user-portal shown above.

For Identity Server versions prior to 5.10.0

You can quickly check whether association worked by logging in to the dashboard (https://localhost:9443/dashboard) and clicking on the Associated User Accounts gadget. You can remove the association from here as well.

If you are using an Identity Servier version prior to IS 5.10.0 then you will have to use the https://localhost:9443/services/UserProfileMgtService?wsdl SOAP service to manage the associations from your application(which is also used by the above-mentioned dashboard). You can check here to see how to work with SOAP services.

The UserProfileMgtService SOAP service has the following two methods:getAssociatedIDsForUser can be used to list the associations of a user
removeAssociateIDForUser can be used to delete the associations of a user

Well, that's it :)

Did you know that you can ask any question you may be having about the WSO2 Identity Server directly from the Identity Server team on the wso2is slack workspace? Join the slack workspace from here and ask your questions in the #users channel.

--

--