Heinrich Ulbricht
Heinrich Ulbricht

Reputation: 10372

How to use a certificate for MS Graph authentication from containerized Node.js Azure Function?

We've got a containerized Azure Function, implemented as Node.js application. The container is pulled from Azure Container Registry.

This Node.js app - which runs in the container - needs to access Microsoft Graph (as application, without user context). Basically like shown here:

https://learn.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-nodejs-console

But with the following differences:

(Why Azure Key Vault? Because we want to use its features like automated renewal.)

How would we implement this? The container part is making things complicated it seems.

Upvotes: 0

Views: 966

Answers (1)

Joy Wang
Joy Wang

Reputation: 42143

You could get the certificate from keyvault.

const { DefaultAzureCredential } = require("@azure/identity");
const { CertificateClient } = require("@azure/keyvault-certificates");

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new CertificateClient(url, credential);

const certificateName = "MyCertificateName";

async function main() {
  const latestCertificate = await client.getCertificate(certificateName);
  console.log(`Latest version of the certificate ${certificateName}: `, latestCertificate);
  const specificCertificate = await client.getCertificateVersion(
    certificateName,
    latestCertificate.properties.version
  );
  console.log(
    `The certificate ${certificateName} at the version ${latestCertificate.properties.version}: `,
    specificCertificate
  );
}

main();

Then get the access token for Microsoft Graph with the adal, don't forget to change the resource to https://graph.microsoft.com, also change the values to yours.

'use strict';

var fs = require('fs');
var adal = require('adal-node');


var AuthenticationContext = adal.AuthenticationContext;

function turnOnLogging() {
  var log = adal.Logging;
  log.setLoggingOptions(
  {
    level : log.LOGGING_LEVEL.VERBOSE,
    log : function(level, message, error) {
      console.log(message);
      if (error) {
        console.log(error);
      }
    }
  });
}

function getPrivateKey(filename) {
  var privatePem = fs.readFileSync(filename, { encoding : 'utf8'});
  return privatePem;
}

/*
 * You can override the default account information by providing a JSON file
 * with the same parameters as the sampleParameters variable below.  Either
 * through a command line argument, 'node sample.js parameters.json', or
 * specifying in an environment variable.
 * privateKeyFile must contain a PEM encoded cert with private key.
 * thumbprint must be the thumbprint of the privateKeyFile.
 * {
 *   tenant : 'naturalcauses.onmicrosoft.com',
 *   authorityHostUrl : 'https://login.windows.net',
 *   clientId : 'd6835713-b745-48d1-bb62-7a8248477d35',
 *   thumbprint : 'C1:5D:EA:86:56:AD:DF:67:BE:80:31:D8:5E:BD:DC:5A:D6:C4:36:E1',
 *   privateKeyFile : 'ncwebCTKey.pem'
 * }
 */
var parametersFile = process.argv[2] || process.env['ADAL_SAMPLE_PARAMETERS_FILE'];

var sampleParameters;
if (parametersFile) {
  var jsonFile = fs.readFileSync(parametersFile);
  if (jsonFile) {
    sampleParameters = JSON.parse(jsonFile);
  } else {
    console.log('File not found, falling back to defaults: ' + parametersFile);
  }
}

sampleParameters = {
  tenant : 'naturalcauses.com',
  authorityHostUrl : 'https://login.windows.net',
  clientId : 'd6835713-b745-48d1-bb62-7a8248477d35',
  thumbprint : 'C15DEA8656ADDF67BE8031D85EBDDC5AD6C436E1',
  privateKeyFile : ''
};

var authorityUrl = sampleParameters.authorityHostUrl + '/' + sampleParameters.tenant;

var resource = 'https://graph.microsoft.com';

turnOnLogging();

var context = new AuthenticationContext(authorityUrl);
var key = getPrivateKey(sampleParameters.privateKeyFile);

context.acquireTokenWithClientCertificate(resource, sampleParameters.clientId, key, sampleParameters.thumbprint, function(err, tokenResponse) {
  if (err) {
    console.log('well that didn\'t work: ' + err.stack);
  } else {
    console.log(tokenResponse);
  }
});

Upvotes: 1

Related Questions