• Share
    • Twitter
    • LinkedIn
    • Facebook
    • Email
  • Feedback
  • Edit
Show / Hide Table of Contents

How to get a system user ticket credential

•
Environment: cloud
Some tooltip text!
• 9 minutes to read
 • 9 minutes to read

To get the ticket, you must send a request containing a signed version of your system user token to the partner system user service endpoint.

The system user token is on of the claims in the id_token received the initial administrative authentication.

Pre-requisites

  • Client secret (obtained when application is registered)
  • ContextIdentifier (tenant identity)
  • System user token (application is authenticated)

There are several ways to obtain a system user ticket:

  1. Use our REST API, or
  2. Use our SOAP API, or
  3. Use one of our nuget packages

All three options require a signed version of the system user token. Please read the How to sign a system user token documentation to learn how to do that part of this flow.

Use the REST API

SuperOffice CRM Online exposes one REST endpoint for conducting the exchange:

https://{environment}.superoffice.com/Login/api/PartnerSystemUser/Authenticate

The following example is demonstrates the HTTP request.

@signed_Token=YOUR_SIGNED_TOKEN
@client_Secret=YOUR_CLIENT_SECRET
@context_Identifier=YOUR_CUSTOMER_ID

POST https://{environment}.superoffice.com/Login/api/PartnerSystemUser/Authenticate
Content-Type: application/json
Accept: application/json

{
    "SignedSystemToken": "{{signed_Token}}",
    "ApplicationToken": "{{client_secret}}",
    "ContextIdentifier": "{{context_Identifier}}",
    "ReturnTokenType": "JWT"
}

Use the SOAP API (NodeJS)

SuperOffice CRM Online exposes one WCF SOAP endpoint for conducting the exchange:

https://onlineenv.superoffice.com/login/services/PartnerSystemUserService.svc

Download the PartnerSystemUserService WSDL

The SOAP envelope should contain 2 header elements and the AuthenticationRequest element in the SOAP body.

<?xml version="1.0" encoding="UTF-8"?>
  <SOAP-ENV:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"
                     xmlns:ns1="http://www.superoffice.com/superid/partnersystemuser/0.1"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xmlns:tns="http://www.superoffice.com/superid/partnersystemuser/0.1"
                     xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header>
      <tns:ApplicationToken>${appToken}</tns:ApplicationToken>
      <tns:ContextIdentifier>${contextId}</tns:ContextIdentifier>
    </SOAP-ENV:Header>
    <ns0:Body>
      <ns1:AuthenticationRequest>
        <ns1:SignedSystemToken>${signedToken}</ns1:SignedSystemToken>
        <ns1:ReturnTokenType>Jwt</ns1:ReturnTokenType>
      </ns1:AuthenticationRequest>
    </ns0:Body>
  </SOAP-ENV:Envelope>

Use a nuget package

We provide the following .NET nuget packages to help perform the task.

SuperOffice.WebApi (preferred)

  • SuperOffice.WebApi (nuget)
  • Sample Code on GitHub

SuperOffice.Crm.Online.Core (legacy)

  • SuperOffice.Crm.Online.Core
  • Sample Code on GitHub

How to get system user ticket

The following example code has an extensive amount of logging to the console. This lets you see the output from each step. The final output is the system user ticket. It performs the following steps:

  1. Read the partner's private PEM file.
  2. Sign system user token.
  3. Send request to SuperOffice.
  4. Gets the response to obtain the JWT.
  5. Validate JWT token.
  6. Extract the system user ticket.

  • REST
  • SOAP
NPM package.json file for NodeJS REST example.

package.json file

{
  "name": "devnet-nodejs-systemuser-rest",
  "version": "1.0.0",
  "description": "Signs system user token and requests system user ticket",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node index.js"
  },
  "author": "AnthonyYates",
  "license": "MIT",
  "dependencies": {
    "axios": "^0.26.1",
    "crypto": "^1.0.1",
    "jsonwebtoken": ">=9.0.0",
    "moment": "^2.22.2"
  }
}

index.js code

const crypto = require('crypto');
const moment = require('moment');
const fs = require('fs');
const axios = require('axios');
const jwt = require('jsonwebtoken');

// specify the environment
// sod      => development
// qastage  => stage
// online   => production
const env = 'sod';

// Partner Application Token (AKA Client Secret)
const appToken = 'YOUR_APPLICATION_TOKEN_GOES_HERE';

// Your Online Sandbox Customer Identifier
const contextId = 'Cust12345';

// SystemUserToken provided as a claim in the callback (Redirect URL)
// when a tenant administrator successfully signs into SuperID.
const systemToken = 'YOUR_SYSTEM_USER_TOKEN_GOES_HERE';

// Partners private key
const privKeyFile = 'privatekey.pem';

// SuperOffice public key (SOD) 
// Open SuperOfficeFederatedLogin.crt in notepad,
// save contents as SuperOfficeFederatedLogin.pem
const publKeyFile = 'SuperOfficeFederatedLogin.pem';

const getSystemUserTicket = async () => {
  try {
    const privateKeyFile = fs.readFileSync(privKeyFile,'utf8');
    const publicKeyFile  = fs.readFileSync(publKeyFile, 'utf8');
  
    // prepare the datetime stamp
    const utcTimestamp = moment.utc().format('YYYYMMDDHHmm');
    const data = `${systemToken}.${utcTimestamp}`;
    
    log('Token.Time: ' + data);
  
    // sign the System User token
    let sign = crypto.createSign('SHA256');
    sign.update(data);
    sign.end();
    sign = sign.sign(privateKeyFile, 'base64');
    const signedToken = `${data}.${sign}`;
    
    log('Signed Token: ' + signedToken);
  
    // send the request
  
    var postData = {
        'SignedSystemToken': `${signedToken}`,
        'ApplicationToken': `${appToken}`,
        'ContextIdentifier': `${contextId}`,
        'ReturnTokenType': 'JWT'
    };
    
    let axiosConfig = {
      headers: {
          'Content-Type': 'application/json;charset=UTF-8',
          "Accept": "application/json;charset=UTF-8"
      }
    };
  
    const jwtRes = await axios.post(`https://${env}.superoffice.com/Login/api/PartnerSystemUser/Authenticate`, postData, axiosConfig);
  
    if(jwtRes.data.IsSuccessful)
    {
      var token = jwtRes.data.Token;
  
      var verifyOptions = {
        ignoreExpiration: true,
        algorithm: ["RS256"]
      };
    
      // validate the JWT and extract the claims
      var decoded = jwt.verify(token, publicKeyFile, verifyOptions);
      
      // write out the ticket to the console, DONE!
      const ticket = decoded["http://schemes.superoffice.net/identity/ticket"];
      return ticket;
    } else {
      log('Getting the System User ticket was unsuccessful: ' + jwtRes.data.ErrorMessage);
    } 
  } catch (error) {
    log("Error: " + error);
  }  
}

function log(message) {
  console.log('')
  console.log(message)
}

// Finally, execute the function to get the system user ticket!

(async () => {
  try {
    const result = await getSystemUserTicket();
    log("System User Ticket: " + result);
  } catch (error) {
    log(error);
  }
})();
NPM package.soap.json file for NodeJS SOAP example.

package.soap.json file

{
  "name": "devnet-nodejs-systemuser-soap",
  "version": "0.0.1",
  "description": "Exchange system user token for system user ticket.",
  "main": "index.js",
  "scripts": {
    "start": "node index.soap.js"
  },
  "author": "AnthonyYates",
  "license": "MIT",
  "dependencies": {
    "crypto": "^1.0.1",
    "jsonwebtoken": ">=9.0.0",
    "moment": "^2.22.2",
    "request": "^2.88.0",
    "xml2js": "^0.4.19"
  }
}

index.soap.js code

const crypto = require('crypto');
const moment = require('moment');
const fs = require('fs');
const request = require('request');
const jwt = require('jsonwebtoken');
const xml2js = require('xml2js');

// Partner Application Token (AKA Client Secret)
const appToken = 'YOUR_APPLICATION_TOKEN_GOES_HERE';

// Your Online Sandbox Customer Identifier
const contextId = 'Cust12345';

// SystemUserToken provided as a claim in the callback (Redirect URL)
// when a tenant administrator successfully signs into SuperID.
const systemToken = 'YOUR_SYSTEM_USER_TOKEN_GOES_HERE';

// Partners private key
const privKeyFile = 'privatekey.pem';

// SuperOffice public key (SOD) 
// Open SuperOfficeFederatedLogin.crt in notepad,
// save contents as SuperOfficeFederatedLogin.pem

const publKeyFile = 'SuperOfficeFederatedLogin.pem';

fs.readFile(privKeyFile, 'utf8', function (err, rsaPrivateKey) {

  if (err) {
      return console.log(err);
  }
  console.log(rsaPrivateKey);
  const utcTimestamp = moment.utc().format('YYYYMMDDHHmm');
  const data = `${systemToken}.${utcTimestamp}`;
  console.log('');
  console.log('Token.Time: ' + data);
  let sign = crypto.createSign('SHA256');
  sign.update(data);
  sign.end();
  sign = sign.sign(rsaPrivateKey, 'base64');
  const signedToken = `${data}.${sign}`;
  console.log('');
  console.log('Signed Token: ' + signedToken);
  var soapEnvelope = `<?xml version="1.0" encoding="UTF-8"?>
  <SOAP-ENV:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"
                                      xmlns:ns1="http://www.superoffice.com/superid/partnersystemuser/0.1"
                                      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                      xmlns:tns="http://www.superoffice.com/superid/partnersystemuser/0.1"
                                      xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header>
      <tns:ApplicationToken>${appToken}</tns:ApplicationToken>
      <tns:ContextIdentifier>${contextId}</tns:ContextIdentifier>
    </SOAP-ENV:Header>
    <ns0:Body>
      <ns1:AuthenticationRequest>
          <ns1:SignedSystemToken>${signedToken}</ns1:SignedSystemToken>
          <ns1:ReturnTokenType>Jwt</ns1:ReturnTokenType>
      </ns1:AuthenticationRequest>
    </ns0:Body>
  </SOAP-ENV:Envelope>`;
  console.log('');
  console.log('SOAP: ' + soapEnvelope);
  // send the SOAP envelope to SuperOffice!
  request.post({
    url: 'https://sod.superoffice.com/login/services/PartnerSystemUserService.svc',
    body: soapEnvelope,
    headers: {
      "Content-Type": "text/xml;charset=UTF-8",
      "SOAPAction": "http://www.superoffice.com/superid/partnersystemuser/0.1/IPartnerSystemUserService/Authenticate"
    }
  }, function (error, response, body) {
    if (!error) {
      // convert the XML response to JSON!
      console.log('');
      console.log('Response: ' + body);
      xml2js.parseString(body, { tagNameProcessors: [xml2js.processors.stripPrefix] }, function (err, result) {
        console.log('');
        if (err) {
            console.log('Error converting XML to JSON!');
        } else {
          console.log('Converted to JSON: ' + JSON.stringify(result));
          // drill into the JSON to determine if token was received.
          var successful = result.Envelope.Body[0].AuthenticationResponse[0].IsSuccessful[0];
          if (successful === 'true') {
            // extract the token
            var token = result.Envelope.Body[0].AuthenticationResponse[0].Token[0];
            console.log('');
            console.log('Token: ' + JSON.stringify(token));
            var verifyOptions = {
              ignoreExpiration: true,
              algorithm: ["RS256"]
            };
            try {
              var publicKEY = fs.readFileSync(publKeyFile, 'utf8');
              // Verify the public SuperOffice certificate is loaded
              // this is used to validate the JWT sent back from SuperOffice
              if (publicKEY) {
                  console.log("good to go!");
              } else {
                  console.log("NOT good to go!");
                  return;
              }
              // validate the JWT and extract the claims
              var decoded = jwt.verify(token, publicKEY, verifyOptions);
              // write out the ticket to the console, DONE!
              console.log('');
              console.log('System User Ticket: ' + decoded["http://schemes.superoffice.net/identity/ticket"]);
            } catch (err) {
              console.log('');
              console.log('Error: ' + err);
              return false;
            }
          } else {
              console.log('Authentication failed and no token was received!');
          }
        }
      });
      } else {
          console.log('Error: ' + error);
      }
  });
});
In This Article
© SuperOffice. All rights reserved.
SuperOffice |  Community |  Release Notes |  Privacy |  Site feedback |  Search Docs |  About Docs |  Contribute |  Back to top