Introduction

For a new project, I must validate Azure Access Tokens in PHP. This requires obtaining the public key to validate the JWT signature. This article shows the process of working with the Azure OpenID Connect Metadata Document to obtain the JWKS URI. The JWKS URI contains the public key material to generate a PKCS#1 public key.

I completed this process previously for Google OIDC Identity Tokens in Python and C#/.NET a couple of years ago. However, duplicating this in PHP is more challenging than usual because Microsoft has decided to drop developing SDKs for PHP except for Azure Storage SDK for PHP.

Microsoft statement [link]:

As of February 2021, the Azure SDK for PHP has entered a retirement phase and is no longer officially supported by Microsoft. This repository will no longer be maintained. If you prefer to work in PHP, you can directly call the Azure REST API in PHP

Rarely is a challenge too difficult, so let’s write the PHP code. Hopefully, the details in this article will help you better understand the low-level details of OpenID Connect and JSON Web Tokens (JWT/JWS).

OpenID Connect Metadata Document

OpenID Connect is an identity layer built on top of the OAuth 2.0 framework. The Metadata Document describes the OpenID Connect provider configuration. Microsoft, Google, Auth0, etc publish this document as a URI on the Internet. The Microsoft URI is: https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration

I will use the CLI curl to fetch this document and the CLI jq to pretty print it.

The current Microsoft metadata document looks like this:

If you are developing authentication clients, then the metadata document has a number of keys that are important to you such as token_endpoint, scopes_supported, authorization_endpoint, etc. Too often I see developers hardcode these values in their software. Instead, these values should be determined from the metadata document.

For this article, the key that we are interested in is jwks_uri. This is the URI for the JSON Web Key Set that contains an array of public signing keys. These keys are using to validate the signatures that are attached to Azure Access Tokens.

At this time, the jwks_uri contains the URI: https://login.microsoftonline.com/common/discovery/v2.0/keys

JSON Web Key Set

I will use curl and jq to fetch the JWKS document:

The current Microsoft JWKS document looks like this:

I am interested in four keys:

  • kid
  • n
  • e
  • x5c

The key kid is the base64url encoded X.509 certificate SHA-1 thumbprint.

The key n is the Modulus. The modulus is the product of two prime numbers used to generate the key pair. Its length, usually expressed in bits, is the key length. Common lengths are 1024, 2048, and 4096 bits.

The key e is the Public Exponent. This is usually a small prime number such as 3, 5, 17,257, or 65537. The private key also has an exponent called the Private Exponent.

The key x5c is the X.509 certificate chain. The value is the public key certificate or certificate chain corresponding to the key used to sign the JWS. I noticed that the certificate issuer is accounts.accesscontrol.windows.net. If you are an Office 365 user, the issuer URL will take you to your Office 365 account.

To create a public key to verify the JWS signature, we only need the values for n and e. I will show how to do that in PHP later in this article. The public key can also be obtained from the x5c value (X.509 certificate chain) which I demonstrate in a complete program.

Creating a Public Key from Modulus and Exponent

This requires the phpseclib version 2.0 package. Years ago, before JSON and YAML became dominant, specifications were written in XML. The phpseclib package supports declaring the values for a public key using XML. This is the easiest method. Encoding very large numbers is challenging. A second version of the program below implements this code: GitHub Gist.

Creating an X.509 Certificate

Creating a certificate from the x5c value is easy. Just add the header and tail strings.

Assuming the above function generated the following certificate written to public-cert.pem:

Verify creating the public key from the certificate with openssl:

Which will output something similar to this:

The truncated output of public-cert.pem to see several important items:

Note the following:

  • Issuer: accounts.accesscontrol.windows.net
  • Not Before: Dec 21 20:50:17 2020 GMT
  • Not After : Dec 20 20:50:17 2025 GMT
  • RSA Public-Key: (2048 bit)

Microsoft is issuing signing keys that are valid for five years. The keys are issued by accounts.accesscontrol.windows.net and are 2048 bits long.

PHP Program

The following code is available on GitHub [link]. I am not using libraries that require composer install, so there is no composer.json. Just run the program like this:

Github Gist

PHP Program implementing Modulus and Exponent

This version requires phpseclib. Run composer install before running the program.

GitHub Gist

More Information

Photography Credits

I write free articles about technology. Recently, I learned about Pexels.com which provides free images. The image in this article is courtesy of Pixabay at Pexels.