Posted on: August 26, 2024 02:59 PM
Posted by: Renato
Views: 162
Usando RS256 para assinar e verificar seu JWT
Christian Eland
Quando falamos em OAuth e OpenID Connect, falamos de JWT.
Sabemos que os JWT devem ser assinados, mas qual algoritmo utilizar?
Usar um algoritmo de assinatura assimétrico no seu JWT é a melhor escolha, pois não haverá necessidade de compartilhar uma chave privada com muitas aplicações.
Usar um algoritmo como RS256 e o endpoint JWKS permite que suas aplicações confiem nos JWTs assinados.
Qual a diferença entre HS256 e RS256?
- HS256: gera um MAC simétrico, precisa compartilhar um “secret” com qualquer cliente ou API que queira verificar o JWT. Por ser um algoritmo simétrico o mesmo “secret” é utilizado tanto na assinatura quanto na verificação. Isso significa que não há como garantir completamente que o JWT foi gerado pela fonte esperada. (como um OIDC OP, por ex)
- RS256: gera uma assinatura assimétrica, o que significa que uma chave privada deve ser utilizada para assinatura do JWT e uma chave pública deve ser utilizada para verificar a assinatura. Isso garante que a fonte esperada assinou o JWT.
Verificando RS256
Vamos nos basear na especificação de JWK (JSON Web Key) . Essa especificação define 2 estruturas de dados de alto nível: JWKS e JWK. As definições:
- JSON Web Key (JWK): Um objeto JSON que representa uma chave criptográfica. Os membros do objeto (JSON) representam as propriedades da chave, incluindo o valor da mesma.
- JWK Set: Um objeto JSON que representa um conjunto de JWKs. O objeto JSON deve ter um membro “key”, que é um array de JWKs.
De uma maneira bem simples, JWKS é um conjunto de chaves contendo as chaves públicas que devem ser usadas para verificar qualquer JWT expedido pelo servidor de autorização.
Num servidor open-source Gluu, a jwks_uri
fica em https://[dominio/oxauth/restv1/jwks
, que retorna por exemplo:
{
"keys" : [ {
"kty" : "RSA",
"e" : "AQAB",
"use" : "sig",
"crv" : "",
"kid" : "fa834459-66c6-475a-852f-444262a07c13_sig_rs256",
"x5c" : [ "MIIDBDCCAeygAwIBAgIhAP+hWbaZnUq8Z1ERfxg9679LMgKrjaNtN02yZoh1TUbgMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwHhcNMjAwNzE0MDUzMDQxWhcNMjAwNzE2MDUzMDUwWjAhMR8wHQYDVQQDDBZveEF1dGggQ0EgQ2VydGlmaWNhdGVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtC0s/6n2mx34ls7rWRQoWdkyY56RicuzGM8xihsYV9GddfcpZhzZFedd4jRAzAonN+/1xeV0H8OvfS6w7fKZehzakOdB+Pb2d2P9V5+Ip1dBBKM+LAknWUgM61liSgwX+uHX9ej8TRn+0TCPlmA5KouUpWEPm3eD0vZUchgBbwbMpLdl8YkrIb+RjUThiJsyQKK75owQtP/wRFl/U4gEeK7oChioZyYaKGYOew3X4xQDkS/bF5ONmQzVxQawFJoPho0Ob9P2XDWtIz9tz0UieGe1wgjCF+nzz+l31p/1er8/UTjPs9gTDQDGP/GYMEocViYHS1WZ0WNSfDJGbdHPRQIDAQABoycwJTAjBgNVHSUEHDAaBggrBgEFBQcDAQYIKwYBBQUHAwIGBFUdJQAwDQYJKoZIhvcNAQELBQADggEBAHZFl9JZ6YsPr6BmAS6h6SnNRpeWX9GrfO0jhhhzsHR/UWTBMWHsb4XXKNZvnmGzsXGEDHU8ep3McgckN7Kc2X3TeZFCjUgYckZJZ61TwJcR9vyMcrPSgQBOhrtkooNYu0HDg5RExc+uwaOER9jiIFKFgQCRtwRRPox8O54HzLNc7m296DchluXtNDIxCs69PNkI2yNmNpxPgH7JXfldhlU2+vjE0G/n/zcK8aa8pCxLeqM07iqLhcYzjNhopKmC0UnwoSyKh7be4oNBk9QbCQ4rdx2zVzmaFT1IietfibGyq3/nP6VcCs0hpJ3808OznOovx3t4VH3kTg5mX8OVVbo=" ],
"exp" : 1594877450248,
"alg" : "RS256",
"n" : "tC0s_6n2mx34ls7rWRQoWdkyY56RicuzGM8xihsYV9GddfcpZhzZFedd4jRAzAonN-_1xeV0H8OvfS6w7fKZehzakOdB-Pb2d2P9V5-Ip1dBBKM-LAknWUgM61liSgwX-uHX9ej8TRn-0TCPlmA5KouUpWEPm3eD0vZUchgBbwbMpLdl8YkrIb-RjUThiJsyQKK75owQtP_wRFl_U4gEeK7oChioZyYaKGYOew3X4xQDkS_bF5ONmQzVxQawFJoPho0Ob9P2XDWtIz9tz0UieGe1wgjCF-nzz-l31p_1er8_UTjPs9gTDQDGP_GYMEocViYHS1WZ0WNSfDJGbdHPRQ"
}, {
"kty" : "RSA",
"e" : "AQAB",
"use" : "sig",
"crv" : "",
"kid" : "2fef95cb-bdb1-4d7e-af4f-e4632dab4773_sig_rs384",
"x5c" : [ "MIIDBDCCAeygAwIBAgIhAKh3wNZIJJxTMNTmZPstkG4qtuB/5tu4Uy9+2JVCDv/tMA0GCSqGSIb3DQEBDAUAMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwHhcNMjAwNzE0MDUzMDQyWhcNMjAwNzE2MDUzMDUwWjAhMR8wHQYDVQQDDBZveEF1dGggQ0EgQ2VydGlmaWNhdGVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApcTN8m+8cK1p5zahgwaC38QlqvxryXIJpyGG+O3SXiY0GxNvzvbw9vwwApXs5f8DIuH/ar1KgdOxWHzFz+RqpwlerhUffbZ9XFDcrFAqvxDr61vgRCZq6kmBpl7TYkaGAELk7jVXbz7fchtJk+Ndbg+TjYwzGuBrO6O9T0IYqzz+vcIv1uHgZdVbj/OR++UYBdgcXlxoTIHRNlwuanvOQs7wix5w4fGsAEjkVHMqqhUvbjqY28x+MeiwZ4TBiyemQg+dJRMgf51YY/HsC5VE9ZbDiJNDeKR/ccl6fUafqYii5/A+okVnfMj5GgdKOWQopmHXEWhx0+iexXYhkfJaxQIDAQABoycwJTAjBgNVHSUEHDAaBggrBgEFBQcDAQYIKwYBBQUHAwIGBFUdJQAwDQYJKoZIhvcNAQEMBQADggEBADyydujhoM5pjHmz1fwWz93Lk+xs3os2fMne9LqeG7NAMSNzB4ysOpH5Gc3cHzWEXsMpkuwpo6wqwy4LIw+mbvDSKWY/C0ShrxwGbtY0FvNEmT8NCvXw3qGxJkLF4DjXJWIIidQsytf/35mrLwlFA33D+Y9kOCEVmClhteo2EgbeBcdy4ZIiVQXowQYTFvgAtBaeg6KKgzrUoI73JR7J9cY3M7lOyKVxpcdzqxzJuZH2EUjFmkztW/D69dPJeaeHYTb6Xn+c9WYarktnKhJnLo7eZasjHzJHX9AuHoVHXF2mYN6AFihrNJO5Sgqei1ay3M+PpoInLd+kW5VYRPL4TOg=" ],
"exp" : 1594877450248,
"alg" : "RS384",
"n" : "pcTN8m-8cK1p5zahgwaC38QlqvxryXIJpyGG-O3SXiY0GxNvzvbw9vwwApXs5f8DIuH_ar1KgdOxWHzFz-RqpwlerhUffbZ9XFDcrFAqvxDr61vgRCZq6kmBpl7TYkaGAELk7jVXbz7fchtJk-Ndbg-TjYwzGuBrO6O9T0IYqzz-vcIv1uHgZdVbj_OR--UYBdgcXlxoTIHRNlwuanvOQs7wix5w4fGsAEjkVHMqqhUvbjqY28x-MeiwZ4TBiyemQg-dJRMgf51YY_HsC5VE9ZbDiJNDeKR_ccl6fUafqYii5_A-okVnfMj5GgdKOWQopmHXEWhx0-iexXYhkfJaxQ"
}, {
"kty" : "RSA",
"e" : "AQAB",
"use" : "sig",
"crv" : "",
"kid" : "639f7204-2f24-4f45-85c7-73c39ee7e4f0_sig_rs512",
"x5c" : [ "MIIDAzCCAeugAwIBAgIgB4umTv9pBV7UtaiKiFenGr8GYhBE2yxXRC9+dGHS89IwDQYJKoZIhvcNAQENBQAwITEfMB0GA1UEAwwWb3hBdXRoIENBIENlcnRpZmljYXRlczAeFw0yMDA3MTQwNTMwNDNaFw0yMDA3MTYwNTMwNTBaMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQClu+DR3C9AQds3el8Aqm5SPTwC47ZYJtCwt26i4aJ+gGbMvio75hYFaQo6nm+f+T3owIO8oBawiBJ6bdsD0bsZ/ca36hWUxNdqmPZfbQTO9WvfqNfmaCYJosgr5eO4voKGBA2pKZ5FAu1zSkFYnlCEdLziFESS57m+F+tOrsmW9UpFp/KCDXcoNWEycCqR+NJbkOzkq9IQdskATUnn8iDWpZBMPbaxcAUkzYlHl5lV0pm8JPJ3gsd3UNC9AgXU39rJ8CULQRMhDa8yL+3M1M+inqY/a1a9OnLJXeKI1QF3arH6hJU+uXBH5rYUmqbXeKr1RtepopYLKCTrEj/KNgg9AgMBAAGjJzAlMCMGA1UdJQQcMBoGCCsGAQUFBwMBBggrBgEFBQcDAgYEVR0lADANBgkqhkiG9w0BAQ0FAAOCAQEAWTeEL5VflWhDvrNkOTlEvOqOoHnOMv/EC5i9kR4fgbfflNGgm6mlEJ4zsVuS2Q/4Xfmp4DWjRfx61Cc30LfZUhw2riUbn+SZl2hM/5CpGgch/bO/k6dFBq/g/KBKR6oWW0o8Odg93LgzZk4lSYq8XBWI0bMwYXTI4SfbcDkKJ+ZAD0YioEawQD6AXRYiSGY6b2/XGEoU/rwuYvKYevn+npEokwE4AQAAY0/VOY8ZSwS1c4xlboRzjPVlgOpdPn6uQ6rkmScXoIoE0F2qOscTAXgVOmYLLcNbnpwmVLjD5EQKQNPOZW6AWWyXY6+KXEHV3J9kedkdghTfKoG0fTB1vw==" ],
"exp" : 1594877450248,
"alg" : "RS512",
"n" : "pbvg0dwvQEHbN3pfAKpuUj08AuO2WCbQsLduouGifoBmzL4qO-YWBWkKOp5vn_k96MCDvKAWsIgSem3bA9G7Gf3Gt-oVlMTXapj2X20EzvVr36jX5mgmCaLIK-XjuL6ChgQNqSmeRQLtc0pBWJ5QhHS84hREkue5vhfrTq7JlvVKRafygg13KDVhMnAqkfjSW5Ds5KvSEHbJAE1J5_Ig1qWQTD22sXAFJM2JR5eZVdKZvCTyd4LHd1DQvQIF1N_ayfAlC0ETIQ2vMi_tzNTPop6mP2tWvTpyyV3iiNUBd2qx-oSVPrlwR-a2FJqm13iq9UbXqaKWCygk6xI_yjYIPQ"
}, {
"kty" : "EC",
"use" : "sig",
"crv" : "P-256",
"kid" : "8be2d1da-3dfd-448a-94e3-70d54cf7cc72_sig_es256",
"x5c" : [ "MIIBeDCCAR6gAwIBAgIhAPTNdOYcEwqwvt5kQUBx0PZJGSws8kcGcg6n105Rc84gMAoGCCqGSM49BAMCMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwHhcNMjAwNzE0MDUzMDQzWhcNMjAwNzE2MDUzMDUwWjAhMR8wHQYDVQQDDBZveEF1dGggQ0EgQ2VydGlmaWNhdGVzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMSrZQI5HljPZ1ABYbdmPsangmRKqg9ESbYI/UCRvJSKyr1FuAlf4QeLzaE763uVXFL2jNqf3Xa0yb8h81eQeG6MnMCUwIwYDVR0lBBwwGgYIKwYBBQUHAwEGCCsGAQUFBwMCBgRVHSUAMAoGCCqGSM49BAMCA0gAMEUCIEaw6XDymS+DOe66yHnvkW0LhKBA31LDlE08/xMrWhIRAiEAyM/VizHxzFjz4O29jQADaCRTj0BbB0DYqrI2JfnK/C4=" ],
"x" : "MSrZQI5HljPZ1ABYbdmPsangmRKqg9ESbYI_UCRvJSI",
"y" : "sq9RbgJX-EHi82hO-t7lVxS9ozan912tMm_IfNXkHhs",
"exp" : 1594877450248,
"alg" : "ES256"
}, {
"kty" : "EC",
"use" : "sig",
"crv" : "P-384",
"kid" : "857380c4-db37-4c2c-8d57-3e46fa988eb5_sig_es384",
"x5c" : [ "MIIBtjCCATugAwIBAgIhAMBZAcWyyC2NKQy04Hx7x/vZoPaGHqY28vjpal/aX5y+MAoGCCqGSM49BAMDMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwHhcNMjAwNzE0MDUzMDQzWhcNMjAwNzE2MDUzMDUwWjAhMR8wHQYDVQQDDBZveEF1dGggQ0EgQ2VydGlmaWNhdGVzMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEiqU4Bh9jCprZvOh4lG5skbGTfX0Ykt+p5SLGSU/Gr2J5Kd4R377zzfko970ANsVBXc3RYSWrcd8WXjxRPbWyDjrk2ii+VYe1Lr77xpZgfOJDWkVgjSaT1ee6NV87o0j8oycwJTAjBgNVHSUEHDAaBggrBgEFBQcDAQYIKwYBBQUHAwIGBFUdJQAwCgYIKoZIzj0EAwMDaQAwZgIxAIFNhgsykTlHnB20yAviQs0iM1WgX2apgXPl0oGe2j3yobpR2SWV+cUi5stiECyv9AIxAPH+ywcHirxbva4GXNt82hKyBlKOxoMbEHeSHEqBVo1nK45EPIje6NRRmGSjbcYniA==" ],
"x" : "iqU4Bh9jCprZvOh4lG5skbGTfX0Ykt-p5SLGSU_Gr2J5Kd4R377zzfko970ANsVB",
"y" : "Xc3RYSWrcd8WXjxRPbWyDjrk2ii-VYe1Lr77xpZgfOJDWkVgjSaT1ee6NV87o0j8",
"exp" : 1594877450248,
"alg" : "ES384"
}, {
"kty" : "EC",
"use" : "sig",
"crv" : "P-521",
"kid" : "4f64c2c8-6695-4a72-9dc4-554da04abc0f_sig_es512",
"x5c" : [ "MIIB/zCCAWGgAwIBAgIhALggJWY04HI04iGYLP5qcrMz+8zuZN4kkehx3A0jWPvDMAoGCCqGSM49BAMEMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwHhcNMjAwNzE0MDUzMDQ0WhcNMjAwNzE2MDUzMDUwWjAhMR8wHQYDVQQDDBZveEF1dGggQ0EgQ2VydGlmaWNhdGVzMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAoaTVRxWZzGW+CR140ceVtQulG8XX4ZSNab60oSYpMAsGl8sQstDTZRUrIJP2x8BdE8aniLcJ7LH2fbXB+oFf+d8AJ89PJ+SIVd5EwK2p5GYHqP87+GpCJSn7U4hnIbUgQsuOxiRy5g+jQn4cfzfa7emHUOw+OcmIkPg5MERFxRa/lUyjJzAlMCMGA1UdJQQcMBoGCCsGAQUFBwMBBggrBgEFBQcDAgYEVR0lADAKBggqhkjOPQQDBAOBiwAwgYcCQgECZmha1CCkrpCqs6WgByn7asvzOj93lU3aadboI9O+pUmlvAOT5YSeKXgbcsQ98eGA5Xh4q/bLTSqZg1JqnV/wGgJBeygLNnYXEilCx+uKcKbyU+kDBLoGt64ToxnIeBPmsZrxprx/XFP9CP8WEJmUkJwt4OfT5P0keGY2t9INCgbCXrw=" ],
"x" : "oaTVRxWZzGW-CR140ceVtQulG8XX4ZSNab60oSYpMAsGl8sQstDTZRUrIJP2x8BdE8aniLcJ7LH2fbXB-oFf-d8",
"y" : "J89PJ-SIVd5EwK2p5GYHqP87-GpCJSn7U4hnIbUgQsuOxiRy5g-jQn4cfzfa7emHUOw-OcmIkPg5MERFxRa_lUw",
"exp" : 1594877450248,
"alg" : "ES512"
}, {
"kty" : "RSA",
"e" : "AQAB",
"use" : "sig",
"crv" : "",
"kid" : "7b0cbe98-54cb-48ba-8a2c-1feb452abf16_sig_ps256",
"x5c" : [ "MIIDazCCAh+gAwIBAgIgLb6FJs95PGb+iFA8tNyIMxA6MI5N1HYnSiuhGiRWpkwwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIDAgEgMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwHhcNMjAwNzE0MDUzMDQ0WhcNMjAwNzE2MDUzMDUwWjAhMR8wHQYDVQQDDBZveEF1dGggQ0EgQ2VydGlmaWNhdGVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/bumTlLseqNPOXOdfNtrPZxOfJVNZDxbkFMThsNUxuoXKGN9Z2D1i6puHwZI1w/I38VKpTTBKfHspKnSMevSh2pKKDLWRtU+F0jHZAd9BFt5texNGjbsJOHjkKw6eTSQTEScSQcyMjhTBnmc0BqmfB0pTy3OUKxspEBpJytvc+Wax7dKiVcGdUarEdd2pXkJRxJuYVI+tKpw4xpVSPXJTbn8u2Cp+2r8ZjDOAetlc3EgEOOuvNdjb22cpX/VN0J5OzxZE1N+hK1a+GLhka+u9k5SBec+SYajB7ocopGhA2fRCWoKQ5X1Ijjb54Omx88yZsXqr5rOK0ugEjkRDZiYwIDAQABoycwJTAjBgNVHSUEHDAaBggrBgEFBQcDAQYIKwYBBQUHAwIGBFUdJQAwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIDAgEgA4IBAQCAb/azcibVFof5NJgodVI59+hHX02c7uNovCeiWrZuHLf8eTa8PtR8r0v2STxISD/46Mh2LISu/F07p6b4Ij5HWFswZDwzCTeRdKIEYmMsigDo65r41T+oCu2jltyBty16Us6UpS1k2gO5aYPkM0P4v7IpXvlcY2JUZEMRUOhpXS5gIYTU0ESGDReSM0blk2hIMuf/xeMjn3tr2UA1JKzW/Qu01tw1sStiHc74NkIou+hopKVcMMpOKUocmPK0x4bmijBzNACMz+r+oUQPKn2esA1uzxqRutp/0RBf5RQoBu8qZF7uIBc9q1MbwS6f/On3RAXg8Gv/bgsQ5kmf7xAn" ],
"exp" : 1594877450248,
"alg" : "PS256",
"n" : "v_bumTlLseqNPOXOdfNtrPZxOfJVNZDxbkFMThsNUxuoXKGN9Z2D1i6puHwZI1w_I38VKpTTBKfHspKnSMevSh2pKKDLWRtU-F0jHZAd9BFt5texNGjbsJOHjkKw6eTSQTEScSQcyMjhTBnmc0BqmfB0pTy3OUKxspEBpJytvc-Wax7dKiVcGdUarEdd2pXkJRxJuYVI-tKpw4xpVSPXJTbn8u2Cp-2r8ZjDOAetlc3EgEOOuvNdjb22cpX_VN0J5OzxZE1N-hK1a-GLhka-u9k5SBec-SYajB7ocopGhA2fRCWoKQ5X1Ijjb54Omx88yZsXqr5rOK0ugEjkRDZiYw"
}, {
"kty" : "RSA",
"e" : "AQAB",
"use" : "sig",
"crv" : "",
"kid" : "f5dcc755-bd1a-49ac-b86d-0c193ec41ce8_sig_ps384",
"x5c" : [ "MIIDazCCAh+gAwIBAgIgJywNmJ6J0dIurCySZLTi0bYOPioEO2d1+a2kxOuVp+AwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAgIFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgIFAKIDAgEwMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwHhcNMjAwNzE0MDUzMDQ1WhcNMjAwNzE2MDUzMDUwWjAhMR8wHQYDVQQDDBZveEF1dGggQ0EgQ2VydGlmaWNhdGVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyABl2vKVxIkMAAzzsxpzpvjWizPFoITc6tlJWjJoNQtjSDANPEkKynl9XuzBf9V5gsbCdygTUa+1EYJabx/cmN0v355qZFhN1F8YecfnkZ/iRLSgN7/1/4edx96vj0DKFIhDpMOr3L3lLEnA2OSwdZ+7yvLzzwbRVa469a/Be/lYGWsxL3tQGpnmszQjiQuktuJgcFv+xa86lgtEW7Hj+5YZp6+ztbZw74ok1cPqwL7kebBXwszS/5WdsyS2KSaj4olYZBXVijFhNgVNxA2/9tyYUPYt9vDbr0s5mDsQE1unOb1EwLfs/diVmKSk/3liZT4bQdu+BqD4mhwcr3sPtwIDAQABoycwJTAjBgNVHSUEHDAaBggrBgEFBQcDAQYIKwYBBQUHAwIGBFUdJQAwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAgIFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgIFAKIDAgEwA4IBAQAcF7auD5v928X11ib7GVxCoLkvC3arYQ41f+9TmqPYHZaGdeT8aA5wBiWFjEPquAzMPb3oI8e7opQylSz3XJaTONdGW0mkAc+KkDVIZdefxyo20wCmCBTU4JBcJPiv9BpYsu5gUSjXqEbLRr3tSBA70gO3dhFaLA2okMwnm0U3peMJCX75n0d2/Vmq9Zkny7QqKviegj9c5VHA71z7TPxkRjYBDKO6mPfwFpW0w/ycMBQxQp5rW3t5fjGuBN/OYC8thsQzhq83WtFaErEf1/O7hp65it8Qn6zeeGVYt7Y2mSKFRJt4opkvJauFmmbhYoRk1zmahovRlwzNg5CU4/yR" ],
"exp" : 1594877450248,
"alg" : "PS384",
"n" : "yABl2vKVxIkMAAzzsxpzpvjWizPFoITc6tlJWjJoNQtjSDANPEkKynl9XuzBf9V5gsbCdygTUa-1EYJabx_cmN0v355qZFhN1F8YecfnkZ_iRLSgN7_1_4edx96vj0DKFIhDpMOr3L3lLEnA2OSwdZ-7yvLzzwbRVa469a_Be_lYGWsxL3tQGpnmszQjiQuktuJgcFv-xa86lgtEW7Hj-5YZp6-ztbZw74ok1cPqwL7kebBXwszS_5WdsyS2KSaj4olYZBXVijFhNgVNxA2_9tyYUPYt9vDbr0s5mDsQE1unOb1EwLfs_diVmKSk_3liZT4bQdu-BqD4mhwcr3sPtw"
}, {
"kty" : "RSA",
"e" : "AQAB",
"use" : "sig",
"crv" : "",
"kid" : "9a18f584-52cd-4917-8c74-a3797b2070f3_sig_ps512",
"x5c" : [ "MIIDazCCAh+gAwIBAgIgErwFJBV9ENFMoq+ftB4seM12nXyBdZ0pz7JbbNJUNTkwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAgMFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgMFAKIDAgFAMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwHhcNMjAwNzE0MDUzMDQ1WhcNMjAwNzE2MDUzMDUwWjAhMR8wHQYDVQQDDBZveEF1dGggQ0EgQ2VydGlmaWNhdGVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsOP0DrkUMb0tDOh8mpmjfn9shZZljcp/tV7zhZt05o+0MM8RGLepDQZWcfnFiuq1kqY3iJeuz9oGfGI+80/KAX0oaVquMuSA+yMbbG/NY7BiQjNCiOBgwTpdAxiLj6zWtrRyq38r1rF3+nI/j5beN8BmBB7c0OSP8GnGKYThQtbALixOTLY9U28dvUKzCupsEH994aYJxaAZdDq+Q95R7khIYCgjeCrEu3RPl1UHenxeEe8UOT5tcehljgIt3cJtej5NYoQMhTOs1Cxpepdsxo7ZE/iV5WUqMr6J5zUDHS4DJ3bfCr+6/XVwt1Dxsd7YtfBPRng6mzE/GMNIIrF95QIDAQABoycwJTAjBgNVHSUEHDAaBggrBgEFBQcDAQYIKwYBBQUHAwIGBFUdJQAwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAgMFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgMFAKIDAgFAA4IBAQBLk9Oz75eLTXFZggyENk7nWqzjNzvJg6t3zGKz7UCMdAtS9ftEMpkofQ04vddW5b7jOv64cDi1uIDSNlptcUpON9moRL9AVIVRRb8EwoiMpCnPaViBFVKA5k6cbSqDCa5VAiEXwz+YiQ/drrPTm2id3hyn9cuFo2Usrvh8rarCY+vuJXeUX9vYos/81ICfAUeetUHmLu+r7jwLtnuy3CfVllhIvyOl1/VMMzayYIjEu9T8aQij9opW9LiNwtq82eCRhzJNy93sZ3QuMU4CjNjx/ucHQWSWeyhDJhHzvGTR1iLRIsQvM2SJS/6rhBnUuJzBBh2aVnfKYNj4bPaLWpNg" ],
"exp" : 1594877450248,
"alg" : "PS512",
"n" : "sOP0DrkUMb0tDOh8mpmjfn9shZZljcp_tV7zhZt05o-0MM8RGLepDQZWcfnFiuq1kqY3iJeuz9oGfGI-80_KAX0oaVquMuSA-yMbbG_NY7BiQjNCiOBgwTpdAxiLj6zWtrRyq38r1rF3-nI_j5beN8BmBB7c0OSP8GnGKYThQtbALixOTLY9U28dvUKzCupsEH994aYJxaAZdDq-Q95R7khIYCgjeCrEu3RPl1UHenxeEe8UOT5tcehljgIt3cJtej5NYoQMhTOs1Cxpepdsxo7ZE_iV5WUqMr6J5zUDHS4DJ3bfCr-6_XVwt1Dxsd7YtfBPRng6mzE_GMNIIrF95Q"
}, {
"kty" : "RSA",
"e" : "AQAB",
"use" : "enc",
"crv" : "",
"kid" : "1b1ae329-8a1b-4f8f-98ad-29fc6fb8460e_enc_rsa1_5",
"x5c" : [ "MIIDAzCCAeugAwIBAgIgYxr5V3K2YXCbxGaZWnkktQCIC4IJoBQtt5O6D3BNzHUwDQYJKoZIhvcNAQELBQAwITEfMB0GA1UEAwwWb3hBdXRoIENBIENlcnRpZmljYXRlczAeFw0yMDA3MTQwNTMwNDZaFw0yMDA3MTYwNTMwNTBaMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC7dGs8+YVgV2bgPC9GHELYPvRmxE278g/nWdlaNhgci2LxmRPFmKLV2vJkOHGh7UguoLw6T3NT8xKm75UfwOoUmeQUOzx1wcuL29I0fNBfMS2SsAR844STstXW/jQyjB0NpqfQ9wOJfY5NWcrEfYJI1x5/YT5u8mtG+2Bez3Qjz58tE3kgymSbQfN4IWZo54zqbW95NjdcxsUbRcYEOL4oErmrig4IpfJMCheEGeX1rNqFgEiu8G8tcYEv8o7cA6lsGRlfQf/juxAf9lHgMLA4yIE9Pjx3+isupMNP22WQMxUQa3dfV4+aQB7HhvKfOQEMvkQxc59tnNNsQWs6R1JAgMBAAGjJzAlMCMGA1UdJQQcMBoGCCsGAQUFBwMBBggrBgEFBQcDAgYEVR0lADANBgkqhkiG9w0BAQsFAAOCAQEAA0X1xdZX2+1i7UusltyrUFHcb4cuyJUmDuJ4S5f3Ei1xijRds4ItET40KaY1SSySwUoLdKAMxbOGNRjvILeyozbbveO73wS5nHLeOku3te7bvGC7ZqIJWWqEby38uHvs6tiLvHZ+uz9hjgqDM88HGFpGijVaDlN09E28wnHyIpcF1EXglJSofpzwLRc6PX4IrwhbPKRKiT+ejPlgABN5lb8S+6RF9txVVozIc/6lG2Ah/YpcYkgh7/pRiVuBYSPKalo2V8l8yJTBWz/zfrU9CNioADQtar66EzhQvsNbQ6WpPZ81KooWRcJwVPI1XJ76weHz9/nzYHfDqtfOGVZ6Rw==" ],
"exp" : 1594877450248,
"alg" : "RSA1_5",
"n" : "wu3RrPPmFYFdm4DwvRhxC2D70ZsRNu_IP51nZWjYYHIti8ZkTxZii1dryZDhxoe1ILqC8Ok9zU_MSpu-VH8DqFJnkFDs8dcHLi9vSNHzQXzEtkrAEfOOEk7LV1v40MowdDaan0PcDiX2OTVnKxH2CSNcef2E-bvJrRvtgXs90I8-fLRN5IMpkm0HzeCFmaOeM6m1veTY3XMbFG0XGBDi-KBK5q4oOCKXyTAoXhBnl9azahYBIrvBvLXGBL_KO3AOpbBkZX0H_47sQH_ZR4DCwOMiBPT48d_orLqTDT9tlkDMVEGt3X1ePmkAex4bynzkBDL5EMXOfbZzTbEFrOkdSQ"
}, {
"kty" : "RSA",
"e" : "AQAB",
"use" : "enc",
"crv" : "",
"kid" : "c0baf666-eb51-4647-b8ac-84ebb05d341c_enc_rsa-oaep",
"x5c" : [ "MIIDAzCCAeugAwIBAgIgQsY6XuS1YBG7DxU7V9nQUE1wavHbiySrVIQAQZ3hXvgwDQYJKoZIhvcNAQELBQAwITEfMB0GA1UEAwwWb3hBdXRoIENBIENlcnRpZmljYXRlczAeFw0yMDA3MTQwNTMwNDZaFw0yMDA3MTYwNTMwNTBaMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWVYhxbWCcRJ29/d66rZxqz9DfYi9Jfk1aehJZPqfu3sq+8N9VMegTXd9Hmix4bbgMaoAFBcFcseiABBQKcTG3fun04PDNQpQj3RgzuMhg3iWRaaM87y59jI9ROgYcSdtQIO8ObR2zzq7i+Wt44j+tna+MDv6md2ehhYfWlqLCuj9WhIZUqQkRTR910AJyZuEBGfTZ9Wey7mDHXzdSHjtr3TKb5whPTSrMwrlIT5KqeXsORLlO0Y4U17UQCZzCUMy3hHT9bctLHoLH3RbwxK69/5WgVNzEam22LiNU6ApyQVGD11EtiKcInlVuA9Jr55xtHZqSFn57B8hsubU2P7k7AgMBAAGjJzAlMCMGA1UdJQQcMBoGCCsGAQUFBwMBBggrBgEFBQcDAgYEVR0lADANBgkqhkiG9w0BAQsFAAOCAQEADON8Dcuq797gOxYkKAqNkE39M7tsdbl4C3Erjyj6H0pIiko8p7mkvqgLmERgdNPrFt+h97kPrmEJ8olf41/NOaOcIjP1l+xSLYp+O6lgVuzgIca7uKsn9JGppeswMWu+7m1BrK+TWPBRmzK560vUP2Ky+GFeH/Y/kslgM/IZyP+UQvpOZpE+KTFwGFZefDaVGf7xgwnYJ8113WVj6CaGj5oGjOnwy4y6mMDaPASD5kLGxbly5ns5LMRmu4xCMsqmxbIGlel20ExTyCkCGXfJ33RQ8rpUy55MCv3ThJ43Yg3hwztlaYX8sg4wQ7Y8nj/pci0Ct7Ey1cRsXlWSyhhCAg==" ],
"exp" : 1594877450248,
"alg" : "RSA-OAEP",
"n" : "llWIcW1gnESdvf3euq2cas_Q32IvSX5NWnoSWT6n7t7KvvDfVTHoE13fR5oseG24DGqABQXBXLHogAQUCnExt37p9ODwzUKUI90YM7jIYN4lkWmjPO8ufYyPUToGHEnbUCDvDm0ds86u4vlreOI_rZ2vjA7-pndnoYWH1paiwro_VoSGVKkJEU0fddACcmbhARn02fVnsu5gx183Uh47a90ym-cIT00qzMK5SE-Sqnl7DkS5TtGOFNe1EAmcwlDMt4R0_W3LSx6Cx90W8MSuvf-VoFTcxGptti4jVOgKckFRg9dRLYinCJ5VbgPSa-ecbR2akhZ-ewfIbLm1Nj-5Ow"
} ]
}
Vemos 10 chaves utilizadas para assinatura e encriptação.
Entendendo os campos:
- alg: é o algoritmo utilizado na chave
- kty: o tipo de chave
- use: é pra que a chave deveria ser utilizada
- x5c: é a corrente do certificado x509
- e: é o exponente para um pem padrão
- n: é o mod para uma pem padrão
- kid: é o único identificador da chave
- x5t: é o SHA-1 thumbprint do certificado x.509
Como verificar um JWT utilizando o endpoint JWKS?
Vou exemplificar um fluxo de autorização OIDC:
Existem várias libs para facilitar a vida dos desenvolvedores (dá uma olhadinha no jwt.io para obter a lista completa). Entre elas a authlib para Python que eu contribuo, e a jsonwebtoken para Node.js.
Basicamente o que a gente vai fazer aqui é:
- Decodificar o JWT e pegar a propriedade kid que tem o id da chave utilizada para esse JWT
- Encontrar a chave utilizada no conjunto JWKS encontrado no jwks_uri do OP.
- Usar a propriedade x5c para gerar o certificado que será utilizado para verificar a assinatura do JWT.
Mão na massa…
Vamos de… Node.js? (já que tenho menos experiência…)
Utilizaremos o pacote jsonwebtoken.
Lembrando que o objetivo é apenas entender a lógica, deixo os tratamentos de erro e as boas práticas com vocês.
Criarei a constante MOCKED_JWS
para utilizarmos como token, que foi criado por chris.gluutwo.org.
Vamos a um exemplo de Node.js:
Output:
Nesse caso, a função retorna o payload do JWT apenas se a assinatura estiver verificada, e também já faz algumas validações. Se você rodar esse mesmíssimo código agora, o jwt.verify()
vai retornar um erro de token expirado (já que essa é uma das validações que o verify()
faz).
Espero que o post tenha sido útil :)
- https://medium.com/@eland.christian/usando-rs256-para-assinar-e-verificar-seu-jwt-4cf3f7b454fd
Donate to Site
Renato
Developer