Get Auth0 token to access api from Salesforce, when Salesforce is IdP

Hi all,

we use Auth0 for our services. Most of the services have an API.
We need to call a couple of these APIs, directly from Salesforce (APEX).
Currently, we use a clientId and a client secret to get a token from Auth0 to call the API.
So for the service, it is always the same user.

So we created a SAML connection between Salesforce and Auth0 where Salesforce is the identity provider. This works pretty well when we open for example the front end of a Service. So the user is redirected to Salesforce and after logging in redirected to the app.

As the next step, we want to be able to call an API from our services within Salesforce using the SAML connection.

  1. User x with SAML identity exists in Salesforce
  2. Salesforce (APEX) gets a token from Auth0 using SAML
  3. Auth0 token retrieved
  4. Salesforce is using the token to call the API from our service (any endpoint)
  5. The service knows what user made the call (for example to store a history of who changed data)

As I tried a couple of things but don’t understand the whole flow, it would be great if I could get some help here.

Thanks,

Marc

Hi @marc.porst,

If I understand your description correctly, you will need to obtain an Access Token in your application and use that to call your backend, where you will validate the token and return the requested resources or request the request.

Does that make sense?

1 Like

Hi @dan.woda ,

let me explain step by step.
For example, we have a user in Auth0 with the user_id “auth|12345”. This user has a role, user_metadata, and permissions.

We have a react app, that uses Auth0 for authentification. With the JWT token the app receives from Auth0 there also comes additional information like user_metadata, roles, etc. to the app.

As the users do have a Salesforce account but have no idea about Auth0 credentials we want them to have the possibility to login via Salesforce.
So we created a SAML connection between Auth0 and Salesforce, where Salesforce is the identity provider.

So this user logs in for the first time in Auth0 a SAML user (identity) is created with the user_id “samlp|SFSAML|12345”. To merge this identity with the real user I created an action and added it to the login flow:

exports.onExecutePostLogin = async (event, api) => {
    if (event.connection.name.includes('SFSAML') && event.user.user_id.includes("samlp|SFSAML")){
        const axios = require('axios');
        const ManagementClient = require('auth0').ManagementClient
        var AuthenticationClient = require('auth0').AuthenticationClient;      
        var request = require('request'); 
        
        const management = new ManagementClient({
            domain: event.secrets.domain,
            clientId: event.secrets.client_id,
            clientSecret: event.secrets.client_secret,
        });
        try{
            let user_id = event.user.user_id;
            let spl = user_id.split("|");
            let last_piece = spl[spl.length-1];
            let res = await management.users.get({ id: 'auth0|'+last_piece }, { headers: { 'bar': 'applied to this request' } });    
            const linkUrl =  event.secrets.domain+`/api/v2/users/${res.data.user_id}/identities`;
            //Get token
            const response = await axios.post( event.secrets.domain+"/oauth/token", {
                grant_type: "client_credentials",
                audience:  event.secrets.domain+"/api/v2/",
                client_id : event.secrets.client_id,
                client_secret : event.secrets.client_secret
            }, {
                    headers: {           
                }
            });

            let access_token = response.data.access_token;        
 
            const link_response = await axios.post(linkUrl, {
                provider: "samlp",
                user_id : user_id
            }, {
                headers: {
                    Authorization: `Bearer ${access_token}` // Replace with your actual token
                }
            });
        }
        catch(err){
            console.error(err)
        }
    }    
};

After the action, we add some parameters to the accessToken and idToken with api.accessToken.setCustomClaim in another action that comes after the link action.

The problem is, at the very first login from the user, where the SAML user gets created, the react app receives the SAML user (samlp|SFSAML|12345) without permissions and user_medata. But the user is linked to the user "auth|12345”. So the user gets an error message. If the user logs in again, it works as expected.

The first idea to fix this was to redirect the user again to the starting point (url of the react app) after the first login with api.redirect.sendUserTo but I don’t know how to get the url of the starting point, including parameters. I already tried event.transaction.redirect_uri.

When I hard-code the starting point, it works as expected. But as the starting point is always different I need another solution here.

Or maybe there is a complete other solution.

Thanks for your help,

Marc

Hi @marc.porst,

Thanks for the additional information. If I understand correctly, the problem is that immediately after the identities are linked, the application does not have the linked identities permissions/roles/metadata in the token.

As a result, the user must do another login to get a token with the correct claims.

You can consider silently authenticating after the account linking to get the correct claims.

Hi @dan.woda ,

thanks for your answer. So you mean in case the app did not receive the user_metadata, or receives a user_id like “samlp%”, we would do another silent login to get the attributes of the primary user?

This would be possible, but I would love to have a more generic solution where we don’t have to include this logic in all our apps. Is there a way in an action to receive the URL where everything has started? So the URL of the app with all it’s GET parameters?

Best,

Marc

Hi @dan.woda,

we solved this topic in another way. I just wanted to add this here, maybe it helps somebody else with the same problem.

In the AuthProvider within our React App, we added another parameter: “windowUrlToRefresh” and gave it the value “window.location.href”.
In the Auth0 action, I can get this value with event.request.query.windowUrlToRefresh
I extended the script where I link the users with:

const windowUrlToRefresh = event.request.query.windowUrlToRefresh;
        if (windowUrlToRefresh != undefined){
          console.log("Will restart process with "+windowUrlToRefresh);
          api.redirect.sendUserTo(windowUrlToRefresh);
        }

So, after the first login when the SAML user was created and linked to the real user the site of the user goes where it started and get’s the token with the information from the real user.
This works now pretty good for us.

Best,

Marc

1 Like

Thanks for the follow up and solution! Glad you were able to get it working.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.