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
- ...