ID Token Validation

ID Token Validation

May 31, 2022·

2 min read

Openid Connect protocol adds id token on top of OAuth for authentication purpose. When you get the id token, the next step is to validate it. For how to get a id token, check my article OAuth and OpenID Connect With Azure AD. Now let me take the id token get from Azure AD as an example to see the validation process.

JWT Decode

Since id token is in valid JWT format, so the first thing is to decode it.

This is a pretty standard process, so we use the jwt-decode to do it.

import jwt_decode from "jwt-decode";

var token = "eyJ0eXAiO.../// jwt token";
var decoded = jwt_decode(token);

Then we get the decoded json result.

First part is the header part.

{
    "typ": "JWT",
    "alg": "RS256",
    "kid": "jS1Xo1OWDj_52vbwGNgvQO2VzMc"
}

Then is the payload part.

{
    "aud": "0640ca50-1722-4f48-9392-b9e2a1f1e0fa",
    "iss": "https://login.microsoftonline.com/25c97843-7dfd-4037-9fc8-4c585dd37ea5/v2.0",
    "iat": 1654037848,
    "nbf": 1654037848,
    "exp": 1654041748,
    "name": "0601",
    "oid": "fd36da28-4687-4f09-9523-da565a80e871",
    "preferred_username": "0601@yaox023.onmicrosoft.com",
    "rh": "0.AXYAQ3jJJf19N0CfyExYXdN-pVDKQAYiF0hPk5K54qHx4PqZALs.",
    "roles": ["Task.Wirte"],
    "sub": "bvFFqAPlDqwhKXJwtYV-FufWS1dDM1uKTXCJWLsTxZE",
    "tid": "25c97843-7dfd-4037-9fc8-4c585dd37ea5",
    "uti": "T0BYZFfeg0esg1B_b9E2AQ",
    "ver": "2.0"
}

Find public key

Let's focus on the header part first. We find the kid parameter, this is how to find the public key.

Normally, you can find a openid meta data file on your identity provider. For Azure AD, the url is https://login.microsoftonline.com/<tenant-id>/v2.0/.well-known/openid-configuration. Send a get request for this url, and we can get a response.

{
    ...
    "jwks_uri": "https://login.microsoftonline.com/<tenant-id>/discovery/v2.0/keys",
    ...
}

The response have many meta data, we only care the jwks_uri parameter here, which contains all the public keys.

Send a get request for this url, we should get a list of keys.

{
    "keys": [
        ...
    ]
}

Find the element with the same kid, we can get:

{
    "kty": "RSA",
    "use": "sig",
    "kid": "jS1Xo1OWDj_52vbwGNgvQO2VzMc",
    "x5t": "jS1Xo1OWDj_52vbwGNgvQO2VzMc",
    "n": "spvQcXWqYrMcvcqQmfSMYnbUC8U03YctnXyLIBe148OzhBrgdAOmPfMfJi_tUW8L9svVGpk5qG6dN0n669cRHKqU52GnG0tlyYXmzFC1hzHVgQz9ehve4tlJ7uw936XIUOAOxx3X20zdpx7gm4zHx4j2ZBlXskAj6U3adpHQNuwUE6kmngJWR-deWlEigMpRsvUVQ2O5h0-RSq8Wr_x7ud3K6GTtrzARamz9uk2IXatKYdnj5Jrk2jLY6nWt-GtxlA_l9XwIrOl6Sqa_pOGIpS01JKdxKvpBC9VdS8oXB-7P5qLksmv7tq-SbbiOec0cvU7WP7vURv104V4FiI_qoQ",
    "e": "AQAB",
    "x5c": [
        "MIIDBTCCAe2gAwIBAgIQHsetP+i8i6VIAmjmfVGv6jANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTIyMDEzMDIzMDYxNFoXDTI3MDEzMDIzMDYxNFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALKb0HF1qmKzHL3KkJn0jGJ21AvFNN2HLZ18iyAXtePDs4Qa4HQDpj3zHyYv7VFvC/bL1RqZOahunTdJ+uvXERyqlOdhpxtLZcmF5sxQtYcx1YEM/Xob3uLZSe7sPd+lyFDgDscd19tM3ace4JuMx8eI9mQZV7JAI+lN2naR0DbsFBOpJp4CVkfnXlpRIoDKUbL1FUNjuYdPkUqvFq/8e7ndyuhk7a8wEWps/bpNiF2rSmHZ4+Sa5Noy2Op1rfhrcZQP5fV8CKzpekqmv6ThiKUtNSSncSr6QQvVXUvKFwfuz+ai5LJr+7avkm24jnnNHL1O1j+71Eb9dOFeBYiP6qECAwEAAaMhMB8wHQYDVR0OBBYEFGzVFjAbYpU/2en4ry4LMLUHJ3GjMA0GCSqGSIb3DQEBCwUAA4IBAQBU0YdNVfdByvpwsPfwNdD8m1PLeeCKmLHQnWRI5600yEHuoUvoAJd5dwe1ZU1bHHRRKWN7AktUzofP3yF61xtizhEbyPjHK1tnR+iPEviWxVvK37HtfEPzuh1Vqp08bqY15McYUtf77l2HXTpak+UWYRYJBi++2umIDKY5UMqU+LEZnvaXybLUKN3xG4iy2q1Ab8syGFaUP7J3nCtVrR7ip39BnvSTTZZNo/OC7fYXJ2X4sN1/2ZhR5EtnAgwi2RvlZl0aWPrczArUCxDBCbsKPL/Up/kID1ir1VO4LT09ryfv2nx3y6l0YvuL7ePz4nGYCWHcbMVcUrQUXquZ3XtI"
    ],
    "issuer": "https://login.microsoftonline.com/25c97843-7dfd-4037-9fc8-4c585dd37ea5/v2.0"
}

Now get the string from the x5c parameter, this is the public key we want.

Verify

We could use a package jsonwebtoken to verify, pass the id token and public key, if verification fails, we should see an error.

const jwt = require("jsonwebtoken");

const idToken = "xxx";
let key = "yyy";
key = "-----BEGIN CERTIFICATE-----\n" + key + "\n-----END CERTIFICATE-----";

jwt.verify(idToken, key);

Other validate

After the verification process, we know it's a valid token. According to your needs, you can do more validations like below.

  • validate aud is your client id
  • validate roles
  • validate groups
  • ...