MicahParks/keyfunc

crypto/rsa: verification error while attempting to parse

Closed this issue · 2 comments

Zibbp commented

Hi,
I'm receiving a crypto/rsa: verification error while attempting to parse a JWT token. Below is the parse code producing the error.

	jwksString := kv.DB().Get("jwks")
	if jwksString == "" {
		return fmt.Errorf("jwks not found")
	}
	jwks, err := keyfunc.NewJSON(json.RawMessage(jwksString))
	if err != nil {
		return fmt.Errorf("failed to parse jwks: %w", err)
	}

	token, err := jwt.Parse(accessToken, jwks.Keyfunc)
	if err != nil {
		fmt.Println(err)
		return fmt.Errorf("failed to parse access token: %w", err)
	}

	fmt.Println(token)

Here are the keys and JWT token (testing/development keys, do not care if they are being posted).
The JWKS being provided to keyfunc.NewJSON() is:

{"keys":[{"use":"sig","kty":"RSA","kid":"f8be68e566eff06dda5f39e06661cf12","alg":"RS256","n":"5V5-iaHxtQ_BOG5eFMzG8az9IEq6mjLhp17fmEnhvN55jZ_LwrAmk9SJtXDnTZfzgn8w9pEH15lbrDkdUx03mnpnE9jUnuje1LXcP22Z-MLK_b7191DrzTLDoeo8mNMLQCOgDFFHDFvlx5U6ZhElDjXIJxsU3QlqXVOgEoxXCMM_4Xaz0LwlZ8zjYWx-qio1EuIDDy2n2nDQh4R430Zrk9FDprHh40axmj8GSb35Y11wo_Hf--w5gD7jxJHdPTBRlKS
hw5lb6U9WVAvqxc4ypk0JXvedSvKcenM24nTfg4LW5hZmAomhThBrWfMJRJLqRgQZb6-ahI_wmd-iL1EwmCtX2CmHLMgvpv-HH0s-0_b9xsHZFQErp-Ocf59H5Cx_Ksxhyy4pah6OwH13eJQXb_ZUhDdMC0qVyk1e80TsxCeYPi5l_D_jWZhYfucKA2x6cx-MZJQkzhI3Uy2X_Dsv8fMfDlvGkAuN6o5uI28tlbV2rWpIMS6uGK1KuS-spbwm1PK53-YoAsob4na61NO3hAEKhxd8PdXeuxFWtws19V8xb2J-ZJ58I39W6lxskojhUsuQrcAOwyMFbBa6FDcweQ1IzqXoWLGipRYQ
N2KncVYuOHK4oMTdYwUN3CCRiPOVLqht_MwVEacUzRwYserMxNwP01VnmxNvkuneO148XYs","e":"AQAB","x5c":["MIIFFDCCAvygAwIBAgIRALngr9LH0kDYjvK3+DiMpiUwDQYJKoZIhvcNAQELBQAwHjEcMBoGA1UEAwwTYXV0aGVudGlrIDIwMjIuMTAuMTAeFw0yMjExMDkxNjQ4MDJaFw0yMzExMTAxNjQ4MDJaMEcxGzAZBgNVBAMMEmdhbnltZWRlLW9hdXRoLXR3bzESMBAGA1UECgwJYXV0aGVudGlrMRQwEgYDVQQLDAtTZWxmLXNpZ25lZDCCAiIwDQYJKoZIh
vcNAQEBBQADggIPADCCAgoCggIBAOVefomh8bUPwThuXhTMxvGs/SBKupoy4ade35hJ4bzeeY2fy8KwJpPUibVw502X84J/MPaRB9eZW6w5HVMdN5p6ZxPY1J7o3tS13D9tmfjCyv2+9fdQ680yw6HqPJjTC0AjoAxRRwxb5ceVOmYRJQ41yCcbFN0Jal1ToBKMVwjDP+F2s9C8JWfM42FsfqoqNRLiAw8tp9pw0IeEeN9Ga5PRQ6ax4eNGsZo/Bkm9+WNdcKPx3/vsOYA+48SR3T0wUZSkocOZW+lPVlQL6sXOMqZNCV73nUrynHpzNuJ034OC1uYWZgKJoU4Qa1nzCUSS6kYEGW
+vmoSP8Jnfoi9RMJgrV9gphyzIL6b/hx9LPtP2/cbB2RUBK6fjnH+fR+QsfyrMYcsuKWoejsB9d3iUF2/2VIQ3TAtKlcpNXvNE7MQnmD4uZfw/41mYWH7nCgNsenMfjGSUJM4SN1Mtl/w7L/HzHw5bxpALjeqObiNvLZW1dq1qSDEurhitSrkvrKW8JtTyud/mKALKG+J2utTTt4QBCocXfD3V3rsRVrcLNfVfMW9ifmSefCN/VupcbJKI4VLLkK3ADsMjBWwWuhQ3MHkNSM6l6FixoqUWEDdip3FWLjhyuKDE3WMFDdwgkYjzlS6obfzMFRGnFM0cGLHqzMTcD9NVZ5sTb5Lp3jt
ePF2LAgMBAAGjJDAiMCAGA1UdEQEB/wQWMBSCEmdhbnltZWRlLW9hdXRoLXR3bzANBgkqhkiG9w0BAQsFAAOCAgEA35ptkBxp8yMDQf7Ppi8ypHA+ZZGIRqI11jlZemDYK8OC5loLEV7NsXqc7ZZwInRyb2zOJzwGrCiUoMdasxCpW922waM2OBHrBCw5VjmhH4Dxqs1p36mwqAzGxxQIH+bgcP1sqIsyijLZoGsSwqOypmqJcX2tXAhB2VStwIgnf2HfSSbvYizlJD6nFTYkD2Grwz8y9/1fvdiBYdgmTY0ZjiXQW2URmspprR7D7945vMEFqNbABdiwarztPuqQIMb4xrnrJYS3
FOkhhB+emC2KlfmhdsS5Fxj65CxWw4UzT8dan/jQrqq+xCBos3L9HdVxVQsY34iIjyq6V3/9oFt6X7nYvJyEmIHUdn5B6deDIawga3gQyZJj9N2b/vTLSH+V+6ZSasSkSImxF2GGjsU7cTjzNzgpNQBdMiIfRxZR/D3SFFn48F14Zou3ftufQMw8ucVQ4YYWwVNqCugmVIQlvug3rR+b4EiIvQy0E2RC0zMYjVMVBtZ9QETU0OmsC8OdujaWsgnjBva/ZC4rHTenPp0z2nKPr6ZwuvJ1pPBiiBUsP16V/NxK0/rWcjdbm9ZoNC5mm5VvX4+9THAJR6RcqKwbckb1ZIiK3QR2k4aB6
N+PqZxNQCptlLBhrJGSr/tjW7zLCvqXiZGlzI99ZXYp3Ww2dDRSGBZNyI21gENuBSA="],"x5t":"7FEExW8zxV-vBGZMhy7T_VkNeTw","x5t#S256":"Om8JpPqPjHHYsyuXog4pfuNyKMH4KBtUqDjTvdALXEM"}]}

The JWT is:

eyJhbGciOiJSUzI1NiIsImtpZCI6ImY4YmU2OGU1NjZlZmYwNmRkYTVmMzllMDY2NjFjZjEyIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2F1dGhlbnRpay50eWNoby56aWJicC5uZXQvYXBwbGljYXRpb24vby9nYW55bWVkZS1kZXYvIiwic3ViIjoiODE0YzUwNWYwNDMwODczM2RkYzA5NmI5ODcyM2JmZjVjYWNmNWIyMzcxZTliZTRkYmVhNjUzMmU0MmQ0NjBkOCIsImF1ZCI6ImU5YzY1NTVjYzgyODFiM2M5ZDNmZ
DVhNGU5ZDMzZDk2MTQ2MjA0MzkiLCJleHAiOjE2NzA2OTM3MDIsImlhdCI6MTY2ODEwMTcwMiwiYXV0aF90aW1lIjoxNjY4MTAxNzAyLCJhY3IiOiJnb2F1dGhlbnRpay5pby9wcm92aWRlcnMvb2F1dGgyL2RlZmF1bHQiLCJuYW1lIjoiVGVzdCIsImdpdmVuX25hbWUiOiJUZXN0IiwiZmFtaWx5X25hbWUiOiIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0Iiwibmlja25hbWUiOiJ0ZXN0IiwiZ3JvdXBzIjpbXSwiY2lkIjoiZTljNjU1NWNjODI4MWIzYzlkM2ZkNW
E0ZTlkMzNkOTYxNDYyMDQzOSIsInVpZCI6IihIL1EjWCM8MXxYVUpkTn1lXFwyYy9AT0R9XFx1d2s5ez5felVcIkNQQEtMRjFTJW5UN2RBOklqSD5WPlo3QTtIaWRuQEdyTn1nSUp5Um44YFAwLTZTckJ8QVwiQjV7aFcnP0I5VmhhKjshbDE2cTtKfFBdViRgVUhXKFMxJEBEcjszVyJ9.5BSkulEbUG5U7lU9OY7dz0H943WSmyfeZ9eNpld85sj6j1tXOV-FM9FllOV4GjICtTVhkg5_lm7mC9-GuQfS1iodhlPyxCRVkXnR6Veyw98bSAtWTsliPcJqs0RFIJam0bb48jhNRX
hP_CDtOLBL108Ak-vOczJB8kt_9jc58yNfqBCCTrybQ5GdVajbEOQQ6tWvzfsznWrqdqHPWBi6r_07u3UUO6cJVmFdhwRbtakOYiWLPhM6QQP6BLdTPiSWNGBdvq61ZYWJ50Kj-WXVg3-JrLl3YtG_N1G30X-Yb0SiRF63fsjX2dZYRBXcqya5l7fjV33PSgsw4kD_rye5HVAMF3OXaQA-yjUNXJ5QuEatTYEgxPD-S9V2RwqSjbA-_UZNRBvQ0pWM7n4JAyM1-s4f-6C85r_IQp0wt6HEvkro8XlkOqwJHTP7c30OGHxHp8SxvcZ25ryL6KDE-0DX8-cQB-vS3F74fhEl6G-cYZE
Sp_st1PxaozymmoZkYXVKRsggxZBxKFRQtxgFp9Cwqr_45Pf7Qvaqlk27IpFfA6JZ0Y-y78MlwTNr-Dtir_S5-yUEYq734zBNdIxFxd1oz9uhQhFs6t1JZd0ohMAppNLrEbOPwzq13e8DTJYkXXOiTQyj87oRXOKrQ1n7Z3URSp_TJMhy-Qj-SAtD_aMlxR4

I'm using Authentik for the OAuth provider. The access token is being retrieved via https://github.com/coreos/go-oidc with the following code.

oauth2Token, err := s.OAuth.Config.Exchange(c.Request().Context(), c.QueryParam("code"))

I'm fairly new to OAuth/OIDC so I could be doing something wrong but I can't seem to find why it's throwing the verification error.

I see the JWKS and JWT you've put into code fences contain newline characters.

If I had to guess, I would say your code is including newline characters in the JWT string, which is actually changing the JWT. If you change the JWT, the signature is invalid.

In my experience, JWTs do not have newline characters, I would recommend removing them before parsing and verifying.

Here is a working example with the JWKS and JWT provided, but I've cleaned up the newline characters.

package main

import (
	"encoding/json"
	"log"

	"github.com/golang-jwt/jwt/v4"

	"github.com/MicahParks/keyfunc"
)

const jwks = `{"keys":[{"use":"sig","kty":"RSA","kid":"f8be68e566eff06dda5f39e06661cf12","alg":"RS256","n":"5V5-iaHxtQ_BOG5eFMzG8az9IEq6mjLhp17fmEnhvN55jZ_LwrAmk9SJtXDnTZfzgn8w9pEH15lbrDkdUx03mnpnE9jUnuje1LXcP22Z-MLK_b7191DrzTLDoeo8mNMLQCOgDFFHDFvlx5U6ZhElDjXIJxsU3QlqXVOgEoxXCMM_4Xaz0LwlZ8zjYWx-qio1EuIDDy2n2nDQh4R430Zrk9FDprHh40axmj8GSb35Y11wo_Hf--w5gD7jxJHdPTBRlKShw5lb6U9WVAvqxc4ypk0JXvedSvKcenM24nTfg4LW5hZmAomhThBrWfMJRJLqRgQZb6-ahI_wmd-iL1EwmCtX2CmHLMgvpv-HH0s-0_b9xsHZFQErp-Ocf59H5Cx_Ksxhyy4pah6OwH13eJQXb_ZUhDdMC0qVyk1e80TsxCeYPi5l_D_jWZhYfucKA2x6cx-MZJQkzhI3Uy2X_Dsv8fMfDlvGkAuN6o5uI28tlbV2rWpIMS6uGK1KuS-spbwm1PK53-YoAsob4na61NO3hAEKhxd8PdXeuxFWtws19V8xb2J-ZJ58I39W6lxskojhUsuQrcAOwyMFbBa6FDcweQ1IzqXoWLGipRYQN2KncVYuOHK4oMTdYwUN3CCRiPOVLqht_MwVEacUzRwYserMxNwP01VnmxNvkuneO148XYs","e":"AQAB","x5c":["MIIFFDCCAvygAwIBAgIRALngr9LH0kDYjvK3+DiMpiUwDQYJKoZIhvcNAQELBQAwHjEcMBoGA1UEAwwTYXV0aGVudGlrIDIwMjIuMTAuMTAeFw0yMjExMDkxNjQ4MDJaFw0yMzExMTAxNjQ4MDJaMEcxGzAZBgNVBAMMEmdhbnltZWRlLW9hdXRoLXR3bzESMBAGA1UECgwJYXV0aGVudGlrMRQwEgYDVQQLDAtTZWxmLXNpZ25lZDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOVefomh8bUPwThuXhTMxvGs/SBKupoy4ade35hJ4bzeeY2fy8KwJpPUibVw502X84J/MPaRB9eZW6w5HVMdN5p6ZxPY1J7o3tS13D9tmfjCyv2+9fdQ680yw6HqPJjTC0AjoAxRRwxb5ceVOmYRJQ41yCcbFN0Jal1ToBKMVwjDP+F2s9C8JWfM42FsfqoqNRLiAw8tp9pw0IeEeN9Ga5PRQ6ax4eNGsZo/Bkm9+WNdcKPx3/vsOYA+48SR3T0wUZSkocOZW+lPVlQL6sXOMqZNCV73nUrynHpzNuJ034OC1uYWZgKJoU4Qa1nzCUSS6kYEGW+vmoSP8Jnfoi9RMJgrV9gphyzIL6b/hx9LPtP2/cbB2RUBK6fjnH+fR+QsfyrMYcsuKWoejsB9d3iUF2/2VIQ3TAtKlcpNXvNE7MQnmD4uZfw/41mYWH7nCgNsenMfjGSUJM4SN1Mtl/w7L/HzHw5bxpALjeqObiNvLZW1dq1qSDEurhitSrkvrKW8JtTyud/mKALKG+J2utTTt4QBCocXfD3V3rsRVrcLNfVfMW9ifmSefCN/VupcbJKI4VLLkK3ADsMjBWwWuhQ3MHkNSM6l6FixoqUWEDdip3FWLjhyuKDE3WMFDdwgkYjzlS6obfzMFRGnFM0cGLHqzMTcD9NVZ5sTb5Lp3jtePF2LAgMBAAGjJDAiMCAGA1UdEQEB/wQWMBSCEmdhbnltZWRlLW9hdXRoLXR3bzANBgkqhkiG9w0BAQsFAAOCAgEA35ptkBxp8yMDQf7Ppi8ypHA+ZZGIRqI11jlZemDYK8OC5loLEV7NsXqc7ZZwInRyb2zOJzwGrCiUoMdasxCpW922waM2OBHrBCw5VjmhH4Dxqs1p36mwqAzGxxQIH+bgcP1sqIsyijLZoGsSwqOypmqJcX2tXAhB2VStwIgnf2HfSSbvYizlJD6nFTYkD2Grwz8y9/1fvdiBYdgmTY0ZjiXQW2URmspprR7D7945vMEFqNbABdiwarztPuqQIMb4xrnrJYS3FOkhhB+emC2KlfmhdsS5Fxj65CxWw4UzT8dan/jQrqq+xCBos3L9HdVxVQsY34iIjyq6V3/9oFt6X7nYvJyEmIHUdn5B6deDIawga3gQyZJj9N2b/vTLSH+V+6ZSasSkSImxF2GGjsU7cTjzNzgpNQBdMiIfRxZR/D3SFFn48F14Zou3ftufQMw8ucVQ4YYWwVNqCugmVIQlvug3rR+b4EiIvQy0E2RC0zMYjVMVBtZ9QETU0OmsC8OdujaWsgnjBva/ZC4rHTenPp0z2nKPr6ZwuvJ1pPBiiBUsP16V/NxK0/rWcjdbm9ZoNC5mm5VvX4+9THAJR6RcqKwbckb1ZIiK3QR2k4aB6N+PqZxNQCptlLBhrJGSr/tjW7zLCvqXiZGlzI99ZXYp3Ww2dDRSGBZNyI21gENuBSA="],"x5t":"7FEExW8zxV-vBGZMhy7T_VkNeTw","x5t#S256":"Om8JpPqPjHHYsyuXog4pfuNyKMH4KBtUqDjTvdALXEM"}]}`

func main() {
	j, err := keyfunc.NewJSON(json.RawMessage(jwks))
	if err != nil {
		log.Fatal(err)
	}
	println(j.Len())

	const token = `eyJhbGciOiJSUzI1NiIsImtpZCI6ImY4YmU2OGU1NjZlZmYwNmRkYTVmMzllMDY2NjFjZjEyIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2F1dGhlbnRpay50eWNoby56aWJicC5uZXQvYXBwbGljYXRpb24vby9nYW55bWVkZS1kZXYvIiwic3ViIjoiODE0YzUwNWYwNDMwODczM2RkYzA5NmI5ODcyM2JmZjVjYWNmNWIyMzcxZTliZTRkYmVhNjUzMmU0MmQ0NjBkOCIsImF1ZCI6ImU5YzY1NTVjYzgyODFiM2M5ZDNmZDVhNGU5ZDMzZDk2MTQ2MjA0MzkiLCJleHAiOjE2NzA2OTM3MDIsImlhdCI6MTY2ODEwMTcwMiwiYXV0aF90aW1lIjoxNjY4MTAxNzAyLCJhY3IiOiJnb2F1dGhlbnRpay5pby9wcm92aWRlcnMvb2F1dGgyL2RlZmF1bHQiLCJuYW1lIjoiVGVzdCIsImdpdmVuX25hbWUiOiJUZXN0IiwiZmFtaWx5X25hbWUiOiIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0Iiwibmlja25hbWUiOiJ0ZXN0IiwiZ3JvdXBzIjpbXSwiY2lkIjoiZTljNjU1NWNjODI4MWIzYzlkM2ZkNWE0ZTlkMzNkOTYxNDYyMDQzOSIsInVpZCI6IihIL1EjWCM8MXxYVUpkTn1lXFwyYy9AT0R9XFx1d2s5ez5felVcIkNQQEtMRjFTJW5UN2RBOklqSD5WPlo3QTtIaWRuQEdyTn1nSUp5Um44YFAwLTZTckJ8QVwiQjV7aFcnP0I5VmhhKjshbDE2cTtKfFBdViRgVUhXKFMxJEBEcjszVyJ9.5BSkulEbUG5U7lU9OY7dz0H943WSmyfeZ9eNpld85sj6j1tXOV-FM9FllOV4GjICtTVhkg5_lm7mC9-GuQfS1iodhlPyxCRVkXnR6Veyw98bSAtWTsliPcJqs0RFIJam0bb48jhNRXhP_CDtOLBL108Ak-vOczJB8kt_9jc58yNfqBCCTrybQ5GdVajbEOQQ6tWvzfsznWrqdqHPWBi6r_07u3UUO6cJVmFdhwRbtakOYiWLPhM6QQP6BLdTPiSWNGBdvq61ZYWJ50Kj-WXVg3-JrLl3YtG_N1G30X-Yb0SiRF63fsjX2dZYRBXcqya5l7fjV33PSgsw4kD_rye5HVAMF3OXaQA-yjUNXJ5QuEatTYEgxPD-S9V2RwqSjbA-_UZNRBvQ0pWM7n4JAyM1-s4f-6C85r_IQp0wt6HEvkro8XlkOqwJHTP7c30OGHxHp8SxvcZ25ryL6KDE-0DX8-cQB-vS3F74fhEl6G-cYZESp_st1PxaozymmoZkYXVKRsggxZBxKFRQtxgFp9Cwqr_45Pf7Qvaqlk27IpFfA6JZ0Y-y78MlwTNr-Dtir_S5-yUEYq734zBNdIxFxd1oz9uhQhFs6t1JZd0ohMAppNLrEbOPwzq13e8DTJYkXXOiTQyj87oRXOKrQ1n7Z3URSp_TJMhy-Qj-SAtD_aMlxR4`

	parsed, err := jwt.Parse(token, j.Keyfunc)
	if err != nil {
		log.Fatal(err)
	}

	println(parsed.Valid)
	println(parsed.Header["kid"].(string))
}
Zibbp commented

Ah, removing the new line characters in the JWT fixed the issue. Thanks for the quick reply!