every open id server has to provide the tenant an endpoint like this :
https://--YOUR DOMAIN----/.well-known/jwks.json
if you visit this endpoint you will see this in json format
{
keys: [
{
alg: 'RS256',
kty: 'RSA',
use: 'sig',
n: 'tTMpnrc4dYlD8MtmPnW3xZNbLxkaGCUwTqeKB4dfLg11dEpMyQEc4JRxUvRzp9tz00r6lkZ1ixcvIiuB_eMVckU8VyFSFWBSAxp5duBk6lRpYk-QjK3kEdPxYLxyW84gNzwMi-XW8zxJbsOa-cRM9sCb62Qz2yfWoQfimoFXsCnVHq496kizO7gZ972JefvTce1_n9dd_1p0K6c14qcCXtF6hbA_gQ0N7h3IyloBqiusKyTsV-ZrMZDldZkI-4v7s49TdcRZgEOvSapMz5YyoDvAWzuWGEiljkjkCOo0Mr5Sioi2x0dBm6nJ2WVYfZrwEF5J',
e: 'AQAB',
kid: 'NTY2MjBCNzQ1RTLPQzk3NzczRRTMQ0E4NzE2MjcwOUFCRkUwRTUxNA',
x5t: 'NTY2MjBCNzQ1RTJPLzk3NzczRUNPO0E4NzE2MjcwOUFCRkUwRTUxNA',
x5c: [Array]
}
]
}
What is x5c?
The "x5c" (X.509 certificate chain which defines how public-key
certificates must be formatted and used) Header Parameter contains the
X.509 public key certificate or certificate chain [RFC5280]
corresponding to the key used to digitally sign the JWS. The
certificate or certificate chain is represented as a JSON array of
certificate value strings. Each string in the array is a
base64-encoded (not base64url-encoded) DER [ITU.X690.2008] PKIX
certificate value. The certificate containing the public key
corresponding to the key used to digitally sign the JWS MUST be the
first certificate. This MAY be followed by additional
certificates, with each subsequent certificate being the one used to
certify the previous one. The recipient MUST validatethe certificate
chain according to RFC 5280 [RFC5280] and consider the certificate
or certificate chain to be invalid if any validation failure
occurs. Use of this Header Parameter is OPTIONAL.
if you check the x5c array, you will see very long string. You have to take this value and separate them for each 64 values. it is very simple. here is an example:
-----BEGIN CERTIFICATE-----
MIIDBzCCAe+gAwIBAgIJY5XAn120Mst4MA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV
BAMTFmRl2e11ZGlrdGt5Mi5hdXRoMC5jb20wHhcNMTkwOTI5MjAxNjE4WhcNMzMw
NjA3MjAxNjE4WjAhMR8wHQYDVQQDExZkZXYtdWe3a3RreTIuYXV0aDAuY29tMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AeIIBCgKCAQEAtTMpnrc4dYlD8MmPnW3xZNbL
xkaGCUwTqeKB4etLg11dEpMyQEc4JRxUvRzp9t656lkZ1ixcvIiuB/eMVckU8VyF
SFWBSAxp5vrBk6lRpYk+QjK3kEdA9PxYLxyW84gNzwMi+XW8zxJbsOa+cRM9sCb6
2Qz2fWoQfimoFXsCnVHq496kp93izO7gZ972JefvTce1/n9dd/1p0K6c14qcCXtF
6hbA/gQ0N7h3IyloBqiusKyTsV+ZrMZDldZkI+4v7s49TdcRZgEOvSapMz5YyoDv
AWzuWGEilCOo0Mr5Sioi2x0dBm6nJ2WVYfZrwEF5JTz9LlKjYAqJ6ETGYKhjkwID
AQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQme5xBKaloQKQr5oxt
7uRlWthe6jAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADopEBABpfpizn
MSJ67HDX358Rav5CYFEeIBeHXrxDQLprKdNzNSxOJ6tRpk6OF0Qs52wCEbrUXYBu
MRjmmmvN3bBHGMmq/g4VPZGDLh/JF5xJjRj13um8Rfua3S2NE4nZUYfPWctk56mN
UUQ9DUkbPRbLEJKCqVSQNagk6TEGe4dfRGdUNvAzDBglMTFOSrY1GAOJdUA1+bPb
3MnSdfyIyxSfPK5oDSQ4puMWKme2ZdGGPj+urSxs1Tuwkv0DxohdV+35WUIJcJPU
ARJecLX7rjyAzqqZE1sJGfsY5ob09380/BTAwHHP/KjiOFhilJ5OoHiU62D+mEKA
DHqlJzoj1VX/3d8=
-----END CERTIFICATE-----
So when you start your verification process:
//you get the token
//you decode the token
//you compare the kid which is in the header of the token
//jwk.kid the one that you get when you visit the /.well-known url above
if (jwk.kid === decodedToken.header.kid){
// in verification process you have to use the decoded code and the certificate
// to verify the signature
}
this process is specific to 'RS256' algorithm. RS256 generates an asymmetric signature, which means a private key must be used to sign the JWT and a different public key must be used to verify the signature. Unlike symmetric algorithms, using RS256 offers assurances that Auth0 is the signer of a JWT since Auth0 is the only party with the private key. For verifying the symmetric algorithms, you have to use private key.