4

I am trying to generate an OAuth token with the SAML 2.0 Bearer Assertion flow in Salesforce.com, but receiving invalid assertion error:

{
  "error_description": "invalid assertion",
  "error": "invalid_grant"
}

The assertion that I am generating is:

    <?xml version="1.0" encoding="UTF-8"?>
    <saml:Assertion
      xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" ID="_S1OBTt6ZmtbsK32e6nMf02kNubxIvCv4" IssueInstant="2015-04-12T15:33:26.414Z">
      <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
        xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">3MVG9Y...1wpi
      </saml:Issuer>
      <Signature
        xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
          <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
          <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
          <Reference URI="#_S1OBTt6ZmtbsK32e6nMf02kNubxIvCv4">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
            <DigestValue>zOTAJJZUy/gT0c6Bpsbc5sArQ9xeJToVP1zQe/SS0FA=</DigestValue>
          </Reference>
        </SignedInfo>
        <SignatureValue>Ne35NiqGR01VxqxTxzJ...sPn8roB/TZZZmyHA==</SignatureValue>
        <KeyInfo>
          <X509Data>
            <X509Certificate>MIIEjzCCA3egAwIBAgIJAPmw2...2XgjN09asKQ30dARPEzdQ==</X509Certificate>
          </X509Data>
        </KeyInfo>
      </Signature>
      <saml:Subject
        xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
        <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
          xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">subhash.bhushan@kaybus.com
        </saml:NameID>
        <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"
          xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
          <saml:SubjectConfirmationData NotOnOrAfter="2015-04-12T15:34:26.414Z" Recipient="https://subhash-kaybus-dev-ed.my.salesforce.com/services/oauth2/token"/>
        </saml:SubjectConfirmation>
      </saml:Subject>
      <saml:Conditions
        xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2015-04-12T15:33:26.414Z" NotOnOrAfter="2015-04-12T15:34:26.414Z">
        <saml:AudienceRestriction
          xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
          <saml:Audience>https://subhash-kaybus-dev-ed.my.salesforce.com/services/oauth2/token</saml:Audience>
        </saml:AudienceRestriction>
      </saml:Conditions>
      <saml:AuthnStatement AuthnInstant="2015-04-12T15:33:26.414Z"
        xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
        <saml:AuthnContext
          xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
          <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
        </saml:AuthnContext>
      </saml:AuthnStatement>
    </saml:Assertion>

I generated a X509 cert locally using the following command, and attached it to my connected app:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 999

The node.js program I am using to generate the assertion is below:

    var fs = require('fs');
    var pd = require('pretty-data').pd;
    var saml20 = require('saml').Saml20;
    var request = require('request');
    var base64url = require('base64url');
    var xmldom = require('xmldom');

    var options = {
      cert: fs.readFileSync(__dirname + '/cert.pem'),
        key: fs.readFileSync(__dirname + '/key.pem'),
      issuer: '3MVG9Y6d_Btp4...apXfJW1wpi',
      lifetimeInSeconds: 60,
      audiences: 'https://subhash-kaybus-dev-ed.my.salesforce.com/services/oauth2/token',
        recipient: 'https://subhash-kaybus-dev-ed.my.salesforce.com/services/oauth2/token',
      // attributes: {
      //   'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress': 'sumukhavadhani@gmail.com',
      //   'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'Sumukh Avadhani'
      // },
      nameIdentifier:       'subhash.bhushan@kaybus.com',
      nameIdentifierFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified'
    };

    var signedAssertion = saml20.create(options);

    request({
      url: 'https://subhash-kaybus-dev-ed.my.salesforce.com/services/oauth2/token',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      rejectUnauthorized:false,
      form: {
            grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer',
            assertion: base64url.encode(signedAssertion)
        }
    }, function(err, body, response) {
      if(err) {
        cb(err)
      } else {
            console.log('body = \n', pd.json(body["body"]));
      }
    });

I am using a free developer salesforce account to do this testing.

I have confirmed that the client ID being mentioned here is the consumer key of my connected app, and the entity ID mentioned in my connected app is the same I am using as token end-point in the assertion. I have enabled all scopes for my connected app, relaxed IP restrictions, created a permission set and added my user to it.

I have gone through the assertion with a fine-toothed comb and compared it line-by-line to the example mentioned in https://help.salesforce.com/HTViewHelpDoc?id=remoteaccess_oauth_SAML_bearer_flow.htm&language=en_US and ensure they match up. Amazingly, when I fire the assertion using a curl command with the Base64URL data:

curl -X POST https://test.salesforce.com/services/oauth2/token -d "grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer" -d "assertion=PD94bWwgdmVy..."

I first get the following error:

{"error_description":"invalid assertion","error":"invalid_grant"}

After a minute, I get:

{"error_description":"expired authorization code","error":"invalid_grant"}

So I guess the assertion is being decoded alright by salesforce.

I am using the generated OAuth token to make subsequent API calls to Salesforce through a canvas app. Is there some setup I should ensure on my connected app?

What am I doing wrong? Any help will be appreciated.

  • In your connected app what permissions have you given? – Mohith Shrivastava Apr 12 '15 at 18:04
  • @MohithShrivastava I have enabled all scopes for my connected app, relaxed IP restrictions, created a permission set and added my user to it. Is there something else specific that you have in mind? – Subhash Bhushan Apr 13 '15 at 1:02
  • May be your problem similar to below query salesforce.stackexchange.com/questions/31904/… – Mohith Shrivastava Apr 13 '15 at 2:34
  • I have seen that post, but my problem seems to be even more generic than that; the assertion itself is deemed to be invalid. But either way, I have already given the permissions mentioned in the post, and changed the connected app settings to what has been advised. – Subhash Bhushan Apr 13 '15 at 3:13
  • I think you are messed with Endpoint URL .Kindly note for developer instance it has to be login.salesforce.com and for sandbox it is test.salesforce.com – Mohith Shrivastava Apr 13 '15 at 4:51

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.