1

I build an apex rest API that is returning base64 to client. API works fine with PostMan/soapUI. When i try to invoke same Apex REST API from my another developer Account I am getting HttpResponse[Status=Unauthorized, StatusCode=401]"|. Initially I was getting Return code 302 and in debug log i saw it was redirecting to domain URL and then i changed End point to domain URL so return code 302 does not appear but now keep getting 401. I checked Salesforce documentation but unable to find anything specific to 401 error code.

Any idea if i am doing something wrong in my code ?

    HttpRequest tokenRequest = new HttpRequest();
    tokenRequest.setMethod('POST');
    tokenRequest.setEndpoint('https://test.salesforce.com/services/oauth2/token');
    String CLIENT_ID = ‘xxxxxxxxxxxxxxxx’;
    String CLIENT_SECRET = ‘xxxxxxxxxxxxxxxx’;
    String USERNAME = ‘xxxxxxxxxxxxxxxx’
    String PASSWORD = ‘xxxxxxxxxxxxxxxx’
    
    tokenRequest.setBody('grant_type=password' + '&client_id='+CLIENT_ID + 
                '&client_secret='+CLIENT_SECRET + '&username='+USERNAME + '&password='+PASSWORD);
    
    Http http1 = new Http();
    HTTPResponse responseToken = http1.send(tokenRequest);
    
    string tran = ‘xxxxxxx03zsTNQAY'; // for test purpose only
    string endpoint = 'https://xxxxx--xxxxxxx.my.salesforce.com/services/apexrest/v1/getdetails?transactionid='+tran;
    HttpRequest request = new HttpRequest();
    request.setHeader('Content-Type', 'application/json');
    request.setHeader('Authorization', 'Bearer ' +responseToken.getBody()); 
    request.setEndpoint(endpoint);
    request.setMethod('GET');
    Http http = new Http();
    HTTPresponse res= http.send(request);
/* Added to handle 302 return code 
        while (res.getStatusCode() == 302) {                
            request.setEndpoint(res.getHeader('Location'));
            res = new Http().send(request);
            system.debug('Calling Again !!! ');
        }
   */
        system.debug(' Location header from respose :'+ res.getHeader('Location'));
        system.debug(' Response :'+ res);
        
    } catch(exception e){
        System.debug('ERROR: '+ e.getMessage());  
    }
8
  • The HTTP 401 Unauthorized client error status response code indicates that the request has not been applied because it lacks valid authentication
    – glls
    Aug 20 at 15:09
  • Thanks for response @gll - I see in debug log that i am getting Access token successfully and no error in that part.
    – Sfdc_1184
    Aug 20 at 15:12
  • you are getting the access token, but your request to https://xxxxx--xxxxxxx.my.salesforce.com/services/apexrest/v1/getdetails?transactionid='+tran is failing ?
    – glls
    Aug 20 at 15:13
  • yes, once control reach to End Point it throw 401 and same endpoint works perfectly fine with soapUI/Postman.
    – Sfdc_1184
    Aug 20 at 15:15
  • are you using the same salesforce endpoint when trying to invoke getdetails in postman than in your apex code?
    – glls
    Aug 20 at 15:18
3

You are not passing only the access_token value, but the whole response body in the Authorization header of the second callout, here:

request.setHeader('Authorization', 'Bearer ' +responseToken.getBody()); 

responseToken.getBody() returns a JSON string like this:

{
  "access_token": "00DR00000008oBT!AQwAQCPqzc_HBE59c80QmEJD4rQKRRc1GRLvYZEq...",
  "instance_url": "https://MyDomainName.my.salesforce.com",
  "id": "https://login.salesforce.com/id/00DR00000008oBTMAY/005R0000000IUUMIA4",
  "token_type": "Bearer",
  "issued_at": "1513887500425",
  "signature": "3PiFUIioqKkHpHxUiCCDzpvSiM2F6//w2/CslNTuf+o="
}

What you must provide in the Authorization header is only the value of access_token property.

You can use JSON.deserializeUntyped to parse that JSON string into a Map<String, Object> from which getting the access_token.

Map<String, Object> authMap = (Map<String, Object>) JSON.deserializeUntyped(responseToken.getBody());
...
request.setHeader('Authorization', 'Bearer ' + authMap.get('access_token'));

By the way, instead of hardcoding the whole endpoint, you can get the instance domain from that JSON:

String endpoint = authMap.get('instance_url') + '/services/apexrest/v1/getdetails?transactionid='+tran;
1
  • Thanks @RubenDG ! It worked perfectly. I completely missed that part.
    – Sfdc_1184
    Aug 20 at 17:46

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.