Make Adaptive Planning API Requests with Workday Credentials
Some links in this article go to the Workday Community. If you don't have
a Community account, request
one.
Workday-synchronized users who log in to Workday and use the
Adaptive Planning
Worklet can run Adaptive Planning
public APIs. Users must create an ISU specifically for making these API requests. These users must provide a token in the credentials
element of Adaptive Planning
API requests instead of a username and password. You can cache this token and use it until it expires. After it expires, you must get a new token. Prerequisites
Prerequisites
Workday Domain and Security Groups
- Verify the ISU users who need API access are part of theSet Up: Adaptive Planning API Accesssecurity domain.
Workday Setup Tasks
- Verify thatSingle Sign-Ontasks are enabled within theUser Sign-ontab in theAdaptive Planningtab.
- Verify thePublic API setuptask is enabled within thePublic APItab in theAdaptive Planningtab.
- Verify an integration system user (ISU) setup task created an ISU specifically for making Workday Adaptive Planning API requests and mapped it to anAdaptive Planninguser account.
Adaptive Planning
User Admin- Verify you see the ISU beginning withPublicAPIISU_in the users list within Administration > Users.
- Verify this user has the level access needed for the APIs they want to run. New ISUs don't receive level access by default.
Steps
Steps
- Get a Certificate and Extract your Public Key.
- Register an API Client in Workday with that certificate.
- Generate a JWT Token, Retrieve Workday access_token, and Retrieve AdaptiveAPIAccessToken.
- Use the AdaptiveAPIAccessToken in anAdaptive PlanningAPI Request.
Get a Certificate and Extract your Public Key
You can create a certificate yourself or purchase a certificate from a well-known certificate authority. For the details on the parameters needed for your X.509 Certificate in Workday, see Concept: X.509 Certificates in Workday.
- Extract the public key from your certificate for uploading to Workday.
- Retain your private key for use in your calling application.
- Paste the certificate into Workday when registering your JWT bearer token. Reference your private key in your script.
Register a Workday API Client
- Register an API Client withClient Grant Type: Jwt Bearer Grantin Workday. See Register an API Client for more information.
- Copy the public key derived for your certificate into thex.509 Certificatein the Register API Client page in Workday.
- ForScope (Functional Area)select.Adaptive Planning
- When you finish registering the API client, copy the resulting fields at the bottom of the page to a text file to use later.
- Workday REST API Endpoint
- Token Endpoint
- Authorization Endpoint
Generate JWT Token, Retrieve Workday access_token, and Retrieve AdaptiveAPIAccessToken
- Use your private key and generate the JWT token by running pseudo code listed below.
- To retrieve a Workday access token, make aPOSTrequest to the Token Endpoint, passinggrant_typeandassertion. Use the Token Endpoint copied after registering your API client in Workday. Example Token Endpoint:https://{host or gateway}/ccx/oauth2/{tenant}/tokenExampleCURLrequest to the Token Endpointcurl --request POST 'https://{host or gateway}/ccx/oauth2/{tenant}/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \ --data-urlencode 'assertion={{the jwt assertion from your certificate}}'
- Retrieve the AdaptiveAPIAccessToken by calling the Workday endpoint using the Workday access token. Use the prioraccess_tokenvalue as the Bearer token in theAuthheader for thisGET.Example Access Token:https://{host or gateway}/ccx/api/planning/v1/{tenant}/adaptiveAPIAccessTokenExampleCURLrequest for the AdaptiveAPIAccessToken:curl --request GET 'https://{host or gateway}/ccx/api/planning/v1/{tenant}/adaptiveAPIAccessToken' \ --header 'Authorization: Bearer {{the prior access_token value}}' \ --data-raw ''
- Call theAdaptive PlanningAPI using the AdaptiveAPIAccessToken in the credentials element of the XML in an HTTPPOST. Example:curl -H "Content-Type: text/xml" -d '<?xml version='1.0' encoding='UTF-8'?><call method="exportLevels" callerName="a string that identifies your client application"><credentials token="ID eyJhbDci0iJSUzUxMiIsUmtpZCI6IdvcmtkYXlfa2V5In0.eyJpc3KiOiJXb3JrZGFZIiwiYXV0aF90aW1lIjoxNTczMTY3NjU2LBjzeXnfynnJd.bztQzBmHeTj1amnHA-r96TdrJK0MXMghUFF1KyjxqIq6ruHU63dJp3JAJn3Eche7SEcoZBVGX4wJgna106pmCqgrrVWMf13Hg_sb_szabal2XN1KEEk1qh8z1IDlbt6qJIL_xyW3J2nNSs5ima3vJUYU5sRQXwXst0GuFWXpy464GyB4oKcscrg28X3dnPO_ytdohMKHsWkqyHQKXFQwoQezFaGy10sp4RRUj0lpOZX8C9oBHDYA58IXxGkqKLJVNPvDND6rGY5fTHQ-yxpe1nz-WqB0boiq9a-dv8b3EBzbelxj2fCPdMbng6kzygDcA2at_7BNQiyzfIovS5AG"/><include versionID="3" inaccessibleValues="false"/><sheet id="3" /></call>' -X POST https://api.adaptiveplanning.com/api/v23
Sample Java Application for Generating a JWT Token
This sample Java application generates a JWT token.
//********************************************************************** // // File: TestPublicAPISample.java // // Copyright 2004-2019 Workday Adaptive Planning. // All Rights Reserved. // // This work contains trade secrets and confidential material of // Workday Adaptive Planning and its use or disclosure in whole or in part // without the express written permission of Workday Adaptive Planning is prohibited. // //********************************************************************** import java.io.FileInputStream; import java.security.KeyStore; import java.security.PrivateKey; import java.security.Signature; import java.text.MessageFormat; //import java.util.Base64; import org.apache.commons.codec.binary.Base64; public class AccessAdaptiveAPI { public static void main(String args[]) { String jwtKeyStoreFileString = "/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/security/JWTkeystore.jks"; String clientIDString = "BlywNDM1NmMtZTk2Mi00NTZiTWEyZjktZWM1NGJiOGQ3Yjca"; String userIdString = "PublicAPIISU_Test"; System.out.println(GetAccessToken(clientIDString,userIdString,jwtKeyStoreFileString)); } public void callAPI() { } public String getAdaptiveAPIToken() { return ""; } public String getJWTToken(String privateKey, String username) { return ""; } public void callWorkdayAPI() { } public static String GetAccessToken(String clientId, String userId, String jwtKeyStore) { String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; String claimTemplate = "'{'\"iss\": \"{0}\", \"sub\": \"{1}\", \"aud\": \"{2}\", \"exp\": \"{3}\"'}'"; try { StringBuffer token = new StringBuffer(); //Encode the JWT Header and add it to our string to sign token.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8"))); //Separate with a period token.append("."); //Create the JWT Claims Object String[] claimArray = new String[4]; //iss claimArray[0] = clientId; //sub claimArray[1] = userId; //aud claimArray[2] = "wd"; //exp claimArray[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300); MessageFormat claims; claims = new MessageFormat(claimTemplate); String payload = claims.format(claimArray); //Add the encoded claims object token.append(Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8"))); //token.append(Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8"))); //Load the private key from a keystore KeyStore keystore = KeyStore.getInstance("JKS"); keystore.load(new FileInputStream(jwtKeyStore), "Workday123!".toCharArray()); PrivateKey privateKey = (PrivateKey) keystore.getKey("Workday", "Workday123!".toCharArray()); //Sign the JWT Header + "." + JWT Claims Object Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(privateKey); signature.update(token.toString().getBytes("UTF-8")); String signedPayload = Base64.encodeBase64URLSafeString(signature.sign()); //Separate with a period token.append("."); //Add the encoded signature token.append(signedPayload); return token.toString(); //System.out.println(token.toString()); } catch (Exception e) { e.printStackTrace(); } return ""; } }
Sample C# Application for Generating a JWT Token
This sample C# application generates a JWT token that replaces the username and password in the credentials element of an
Adaptive Planning
API request.This sample code requires a NuGet page. Required NuGet package:
System.IdentityModel.Tokens.Jwt
var clientId = "BlywNDM1NmMtZTk2Mi00NTZiTWEyZjktZWM1NGJiOGQ3Yjca";//Client ID from workday API Client var isu = "PublicAPIISU_Test"; //the ISU var timeout = (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() / 1000 + 300).ToString(CultureInfo.InvariantCulture); var environment = "wd"; var pfxFilePath = @"C:\temp\JWTkeystore2.pfx"; var pfxPassword = "Workday123!"; var payload = new JwtPayload { {"iss", clientId}, {"sub", isu}, {"aud", environment}, {"exp", timeout }, }; var signingCredentials = new X509SigningCredentials(new X509Certificate2(pfxFilePath, pfxPassword), SecurityAlgorithms.RsaSha256); // the matching PKCS #12 file with private key var jwtHeader = new JwtHeader(signingCredentials); var secToken = new JwtSecurityToken(jwtHeader, payload); var handler = new JwtSecurityTokenHandler(); var tokenToWorkday = handler.WriteToken(secToken); Console.WriteLine(tokenToWorkday);
Use the AdaptiveAPIAccessToken in an Adaptive Planning API Request
Adaptive Planning
API RequestOnce you set up Workday for
Adaptive Planning
public API access, the credentials element of Adaptive Planning
API requests use the AdaptiveAPIAccessToken instead of a username and password. Basic authentication with username and password won't work. See Adaptive Planning REST API and API Methods for more.Example AdaptiveAPIAccessToken in an Adaptive Planning API Request
Adaptive Planning
API Request<?xml version='1.0' encoding='UTF-8'?> <call method="exportLevels" callerName="a string that identifies your client application"> <credentials token="ID eyJhbDci0iJSUzUxMiIsUmtpZCI6IdvcmtkYXlfa2V5In0.eyJpc3KiOiJXb3JrZGFZIiwiYXV0aF90aW1lIjoxNTczMTY3NjU2LBjzeXnfynnJd.bztQzBmHeTj1amnHA-r96TdrJK0MXMghUFF1KyjxqIq6ruHU63dJp3JAJn3Eche7SEcoZBVGX4wJgna106pmCqgrrVWMf13Hg_sb_szabal2XN1KEEk1qh8z1IDlbt6qJIL_xyW3J2nNSs5ima3vJUYU5sRQXwXst0GuFWXpy464GyB4oKcscrg28X3dnPO_ytdohMKHsWkqyHQKXFQwoQezFaGy10sp4RRUj0lpOZX8C9oBHDYA58IXxGkqKLJVNPvDND6rGY5fTHQ-yxpe1nz-WqB0boiq9a-dv8b3EBzbelxj2fCPdMbng6kzygDcA2at_7BNQiyzfIovS5AG"/> <include versionID="3" inaccessibleValues="false"/> <sheet id="3" /> </call>