0

I need to create service that calls graph api to access company data. In order to authenticate I need JWT token from Azure Active Directory. The authentication will be using application mode with signing certificate. I tried to use MSAL node ConfidentialClientApplication but the service needs to use http proxy to connect to internet. To my knowledge MSAL node does not support this and calls result in library being unable to resolve the address of "https://login.microsoftonline.com". How can I make MSAL node use the proxy or get JWT token without use od MSAL?

mr100
  • 4,340
  • 2
  • 26
  • 38

1 Answers1

1

In order to get JWT token from azure active directory without MSAL node, one have to generate proper JWT token on its own and then sign it with certificate private key. The header of the token consists of following fields:

{
  typ: "JWT",
  alg: "RS256",
  kid: "156E...",
  x5t: "iTYVn..."
}
  • "kid" is the thumbprint of the certificate used to sign the request - here is a good example how to obtain it for pfx file with powershell https://stackoverflow.com/a/32980899/3588432
  • "x5t" is base64 encoded and sanitized certificate thumbprint.

Sanitization of base64 encoded string means:

  • trimming "=" signs at the end
  • replace "/" with "_"
  • replace "+" with "-"

Exemplary C# code for the sanitization:

var sanitized = s.Split('=')[0].Replace('+', '-').Replace('/', '_');

and JS code:

var sanitized = s.split('=')[0].replace('+', '-').replace('/', '_');

The payload of the token consists of the following fields:

{
  aud: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
  iss: "{clientId}",
  nbf: 1617952610,
  exp: 1617953210,
  sub: "{clientId}",
  jti: "e13efcf..."
}
  • {tenantId} and {clientId} are Azure AD data of application we are authenticating to
  • "nbf" is the time when the token will began to be valid, normally it is time the token got generated. It has unix epoch format https://en.wikipedia.org/wiki/Unix_time and is an integer.
  • "exp" - the time the token expires in unix epoch format.
  • "jti" - a unique token identifier. It may be random generated guid. Should be different for every request.

An example how to get "nbf" value in JavaScript:

var nbf = Math.floor(new Date().getTime() / 1000);

When ready header and payload should be serialized (with sanitization) on concatenated with ".":

var token = JSON.stringify(header) + "." + JSON.stringify(payload);

Then we need to sign it with certificate private key, encode it with base 64 (with sanitization) and prepare a clientAssertion value:

var clientAssertion = token + "." + signedToken;

As a last step can send request to get JWT token:

const body = new URLSearchParams();

const token = await fetch("https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token", {
    agent: new HttpsProxyAgent("http://..."),
    body: new URLSearchParams({
      "client_assertion": clientAssertion,
      "client_id": "{clientId}",
      "scope": "https://graph.microsoft.com/.default"
      "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
      "grant_type": "client_credentials"
    }),
    method: "POST",
    headers: {
        "content-type": "application/x-www-form-urlencoded"
    }
})
.then(response => response.json().access_token);
mr100
  • 4,340
  • 2
  • 26
  • 38