5

I have read the full documentation and have few questions on how named credential works.

I have written a custom provider like this:

/**
 * Description of the class
 * <p /><p />
 * @author ****
 */
global class MulesoftAuthProvider extends Auth.AuthProviderPluginClass {

    public String redirectUrl; // use this URL for the endpoint that the authentication provider calls back to for configuration
    private String key;
    private String secret;
    private String authUrl;    // application redirection to the Concur website for authentication and authorization
    private String accessTokenUrl; // uri to get the new access token from concur  using the GET verb
    private String customMetadataTypeApiName  = 'MulesoftInternalAuthProvider__mdt'; // api name for the custom metadata type created for this auth provider
    private String userAPIUrl; // api url to access the user in concur
    private String userAPIVersionUrl; // version of the user api url to access data from concur


    global String getCustomMetadataType() {
        return customMetadataTypeApiName;
    }

    global PageReference initiate(Map<string,string> authProviderConfiguration, String stateToPropagate) {
        /*//authUrl = authProviderConfiguration.get('Authorize_Endpoint_URL__c');
        accessTokenUrl = authProviderConfiguration.get('Token_Endpoint_URL__c');
        key = authProviderConfiguration.get('ConsumerKey__c');
        secret = authProviderConfiguration.get('ConsumerSecret__c');
        //Here the developer can build up a request of some sort , Ultimately they’ll return a URL where we will redirect the user
        //String url = accessTokenUrl + '?grant_type=client_credentials&client_id=' + key + '&client_secret=' + secret;
        return new PageReference(url);*/

        authUrl = authProviderConfiguration.get('Authorize_Endpoint_URL__c');
        key = authProviderConfiguration.get('ConsumerKey__c');
        //Here the developer can build up a request of some sort , Ultimately they’ll return a URL where we will redirect the user
        String url = authUrl + '?client_id=' + key + '&client_=' + redirectUrl + '&state=' + stateToPropagate;
        return new PageReference(url);
    }

    global Auth.AuthProviderTokenResponse handleCallback(Map<string,string> authProviderConfiguration, Auth.AuthProviderCallbackState state) {
        //Here, the developer will get the callback with actual protocol.
        //Their responsibility is to return a new object called AuthProviderToken
        //This will contain an optional accessToken and refreshToken
        key = authProviderConfiguration.get('ConsumerKey__c');
        secret = authProviderConfiguration.get('ConsumerSecret__c');
        accessTokenUrl = authProviderConfiguration.get('Token_Endpoint_URL__c');
        System.debug('state--->' +state);

        Map<String,String> queryParams = state.queryParameters;
        String code = queryParams.get('code');
        String sfdcState = queryParams.get('state');

        HttpRequest req = new HttpRequest();
        String url = accessTokenUrl + '?code=' + code + '&client_id=' + key + '&client_secret=' + secret;
        req.setEndpoint(url);
        req.setHeader('Content-Type', 'application/xml');
        req.setMethod('GET');

        Http http = new Http();
        HTTPResponse res = http.send(req);
        String responseBody = res.getBody();
        String token = getTokenValueFromResponse(responseBody, 'Token', null);

        return new Auth.AuthProviderTokenResponse('Concur', token, 'refreshToken', sfdcState);
    }


    global Auth.UserData getUserInfo(Map<string,string> authProviderConfiguration, Auth.AuthProviderTokenResponse response) {
        //Here the developer is responsible for constructing an Auth.UserData object
        String token = response.oauthToken;
        HttpRequest req = new HttpRequest();
        userAPIUrl = authProviderConfiguration.get('API_User_Url__c');
        userAPIVersionUrl = authProviderConfiguration.get('API_User_Version_Url__c');
        req.setHeader('Authorization', 'OAuth ' + token);
        req.setEndpoint(userAPIUrl);
        req.setHeader('Content-Type', 'application/xml');
        req.setMethod('GET');

        Http http = new Http();
        HTTPResponse res = http.send(req);
        String responseBody = res.getBody();
        String id = getTokenValueFromResponse(responseBody, 'LoginId', userAPIVersionUrl);
        String fname = getTokenValueFromResponse(responseBody, 'FirstName', userAPIVersionUrl);
        String lname = getTokenValueFromResponse(responseBody, 'LastName', userAPIVersionUrl);
        String flname = fname + ' ' + lname;
        String uname = getTokenValueFromResponse(responseBody, 'EmailAddress', userAPIVersionUrl);
        String locale = getTokenValueFromResponse(responseBody, 'LocaleName', userAPIVersionUrl);
        Map<String,String> provMap = new Map<String,String>();
        provMap.put('what1', 'noidea1');
        provMap.put('what2', 'noidea2');
        return new Auth.UserData(id, fname, lname, flname, uname,
            'what', locale, null, 'Concur', null, provMap);
    }

    private String getTokenValueFromResponse(String response, String token, String ns) {
        Dom.Document docx = new Dom.Document();
        docx.load(response);
        String ret = null;

        dom.XmlNode xroot = docx.getrootelement() ;
        if (xroot != null) {
            ret = xroot.getChildElement(token, ns).getText();
        }
        return ret;
    }
}

Now see the initiate snippet:

global PageReference initiate(Map<string,string> authProviderConfiguration, String stateToPropagate) {
    /*//authUrl = authProviderConfiguration.get('Authorize_Endpoint_URL__c');
    accessTokenUrl = authProviderConfiguration.get('Token_Endpoint_URL__c');
    key = authProviderConfiguration.get('ConsumerKey__c');
    secret = authProviderConfiguration.get('ConsumerSecret__c');
    //Here the developer can build up a request of some sort , Ultimately they’ll return a URL where we will redirect the user
    //String url = accessTokenUrl + '?grant_type=client_credentials&client_id=' + key + '&client_secret=' + secret;
    return new PageReference(url);*/

    authUrl = authProviderConfiguration.get('Authorize_Endpoint_URL__c');
    key = authProviderConfiguration.get('ConsumerKey__c');
    //Here the developer can build up a request of some sort , Ultimately they’ll return a URL where we will redirect the user
    String url = authUrl + '?client_id=' + key + '&client_=' + redirectUrl + '&state=' + stateToPropagate;
    return new PageReference(url);
}

Now named credentials makes it mandatory to use a redirection logic, which normal oauth has, user has to navigate to the provider site, give his credentials and then get a code, with that code he will exchange it with access token in handleCallback method.

But what if I want to use client credentials oauth flow with named credentials, this wont work. Client credentials directly passes Client key and Client secret in the header to get access token.

I tried changing the initiate logic to this:

//authUrl = authProviderConfiguration.get('Authorize_Endpoint_URL__c');
    accessTokenUrl = authProviderConfiguration.get('Token_Endpoint_URL__c');
    key = authProviderConfiguration.get('ConsumerKey__c');
    secret = authProviderConfiguration.get('ConsumerSecret__c');
    //Here the developer can build up a request of some sort , Ultimately they’ll return a URL where we will redirect the user
    String url = accessTokenUrl + '?grant_type=client_credentials&client_id=' + key + '&client_secret=' + secret;
    return new PageReference(url);

but it then redirects to access token page and named credential authorization is still showing pending.

If i return null, then it gives internal server error.

Any workaround for this?

  • Just wanted to say thanks for posting this question as it is the first implementation of this I have seen and the documentation is not that helpful. I do not have anything to add that would help but believe this will be very helpful to the community so +1 from me – Eric Sep 6 '18 at 2:33
  • Thanks @Eric for your comments, I am stuck here, lets see if sfdcfox or anybody from community has to share any views on this. – Nagendra K S Sep 6 '18 at 2:49
  • I see that the twitter API does not use a "Authorization URL" , can someone suggest how have they managed to authenticate through named credential, like code wise, how have they overcome the redirection part. – Nagendra K S Sep 6 '18 at 6:24
  • I have the exact same problem; Happy to have found this early in my development cycle. – Marco Pietersen Sep 17 '18 at 7:26
  • Did you find a solution to this? – Robs Oct 4 '18 at 19:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.