This is sample repository of code and helper function which I created for requesting Azure AD Tokens with the use of certificate credentials in Oauth2 Client Credentials Flow.
Contents
Dependencies | NPM Description | Use in project |
---|---|---|
jsonwebtoken | An implementation of JSON Web Tokens | Creation and sign-in of tokens |
uuid | For the creation of RFC4122 UUIDs | JTI claim in token |
axios | Promise based HTTP client for the browser and node.js | Used to call Azure AD Token Endpoint |
This package has been tested in mainstream versions of Linux, MacOS and Windows 10, with Node versions starting from 12.
OS | Result |
---|---|
Linux | ☑ |
- Helpful example at redthunder.blog for Node.JS was used
to generate X5T header in JWT tokens. The author is credited in the actual code, and in this readme as well.
// code below from https://redthunder.blog/2017/06/08/jwts-jwks-kids-x5ts-oh-my/ var sigOctets = shaSig.split(":"); var sigBuffer = Buffer.alloc(sigOctets.length) for(var i=0; i<sigOctets.length; i++){ sigBuffer.writeUInt8(parseInt(sigOctets[i], 16), i); } //Perform base64url-encoding as per RFC7515 Appendix C // code
- OpenSSL is used in helper function for generating RSA key pair and X5T
- Example for ca.conf was used from Github Gist by https://github.com/klingerf
- This is needed for the creation of X509 rsa key pair, if you have production use case review carefully all params in the CA.CNF file and modify appropriately.
The documentation for Microsoft Identity Platform authentication via certificate credentials has been main source for information for creating this example
The flow is sheer genius IMO: Embed JWT token in your request for the Azure AD request, get Access Token in response, Voila!
- Create Token: Create and sign JWT token with following claims using the JSONWEBTOKEN library
// Example, peek code for actual implementation var claims = { "aud": `https://sts.windows.net/${tenantinfo}/`, "iss": appid, "sub": appid, "jti":"guid", "exp":"date", "iat":"date" } // Code includes infor about the headers used
- Request: Send the token to Azure AD. Azure AD will check the signature with the public key that is stored in Azure AD for your application registration
//Example of request payload
{
grant_type: "client_credentials",
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
client_id: appid,
client_assertion: "embeddedJWTTokenHere",
resource: "TheAPIbeingCalled"
}
-
Response: If the Signature checks Azure AD will provide the client with new access token in the response.
- this token is signed with private key of Azure AD, and meant to be verified by the Public key from tenant metadata (.well-known) by the API verifying this token
-
Use the token to consume Azure AD protected API's
- For this you need to have openssl and installed, and available directly as openssl from command line without any path specified
- In Linux openssl is often pre-installed
- To generate a public/private pair key, you can use this command with openssl
openssl req -newkey rsa:4096 -new -x509 -days 730 -keyout private.pem -out public.pem
- Store these keys
- Populate values for appId and tenantId with values gotten from your Azure AD registration app
// from .env file at root directory
APP_ID=281dbb41-4sd7-45cb-vc21-9748584775z3 //APP ID on Azure AD
TENANT_ID=ds21563-358c-4fed-b0bf-73679c851aa0 //Azure AD Tenant ID
TENANT_URL=https://login.microsoftonline.com/ds21563-358c-4fed-b0bf-73679c851aa0/oauth2/token //login URL with Azure AD Tenant ID
PRIVATE_KEY=private.pem //private key from step 1
PUBLIC_KEY=public.pem //public key from step 1
PASSPHRASE=TEST //passphrase used for private key generation
ROOT_DIR=./ //root dir where keys can be find
Navigate to the project root
and start by installing depedencies with
npm install
Then create configuration
npm run createConfig
// expected result: config file created at \nodeconfig.json
*(you can also use existing application)
- Go to 'Certificates and Secrets' use the 'upload certificate' to upload the public1.pem key
- If the upload was successful you will see the public key in the portal under 'Certificates'
Expected response includes the token:
AAD Response: { token_type: 'Bearer', expires_in: '3599', ext_expires_in: '3599', expires_on: '1611044393', not_before: '1611040493', resource: '784b0133-29b4-4d65-8168-f15477c4620b', access_token: 'g' }
Congratz. You've completed the workflow!