如何在Golang中验证JWE令牌

huangapple go评论90阅读模式
英文:

How to validate JWE token in Golang

问题

我有两个问题,但首先我想提供一些背景信息:

在我们的 Web 应用程序中,我们使用 NextAuth 生成 JWT 令牌,然后将其附加到针对我们的 Golang 服务器(用于获取资源)的请求中。

生成的令牌似乎是通过 A256GCM 生成的 JWE 令牌。在我们的 Golang 服务器中,我们想要验证令牌并提取其中的一些自定义声明。也就是说,我们在解密方面遇到了困难。我们使用 go-jose 如下所示:

rawToken := `eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..aiIqD7-cU8Hu92F8.Kx2k99cyLYJR1P0xK_1wUsVO521T7kYSKx-OEutVJcpzbX27hZH0kh2MlBLxQHdmc8q4uXglhjl4JE3nTp_c6nOjga-faHyxYqKrZGJFLlu9MC4JVUWyonX6doFq0gl3UX9ABtP2t35Qly-w1qKH8BdG9x4iB1YM-yvs1w-HpBbMFQR7U7X4oHWIh_YJQlWADesYq6da7A97GSSXs2Go6yb7SH5WWd7iQzDu-UO6eg._PqujCUyMUqOkID80vJiDw`
key := []byte("thisisaverylongtextusedforhashing")

enc, err := jwt.ParseEncrypted(rawToken)
if err != nil {
    panic(err)
}

out := jwt.Claims{}
if err := enc.Claims(key, &out); err != nil {
    panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)

我们得到的错误信息是:
panic: square/go-jose: error in cryptographic primitive

附注:我传递给 NextAuth 用于 JWE 生成的密钥是 thisisaverylongtextusedforhashing

我想在我的 Golang 服务器中验证的原始 JWE 令牌是:eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..aiIqD7-cU8Hu92F8.Kx2k99cyLYJR1P0xK_1wUsVO521T7kYSKx-OEutVJcpzbX27hZH0kh2MlBLxQHdmc8q4uXglhjl4JE3nTp_c6nOjga-faHyxYqKrZGJFLlu9MC4JVUWyonX6doFq0gl3UX9ABtP2t35Qly-w1qKH8BdG9x4iB1YM-yvs1w-HpBbMFQR7U7X4oHWIh_YJQlWADesYq6da7A97GSSXs2Go6yb7SH5WWd7iQzDu-UO6eg._PqujCUyMUqOkID80vJiDw

英文:

I've got 2 questions but first I want to provide some context:

On our webapp, we are using NextAuth to generate jwt tokens which then we attach to requests against our Golang server (for fetching resources).

The generated tokens seem to be JWE tokens generated via A256GCM. In our golang server we want to validate the token and extract a few custom claims of it. That said, we're struggling to find a way to do the decryption. We're using go-jose as follows:

rawToken := `eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..aiIqD7-cU8Hu92F8.Kx2k99cyLYJR1P0xK_1wUsVO521T7kYSKx-OEutVJcpzbX27hZH0kh2MlBLxQHdmc8q4uXglhjl4JE3nTp_c6nOjga-faHyxYqKrZGJFLlu9MC4JVUWyonX6doFq0gl3UX9ABtP2t35Qly-w1qKH8BdG9x4iB1YM-yvs1w-HpBbMFQR7U7X4oHWIh_YJQlWADesYq6da7A97GSSXs2Go6yb7SH5WWd7iQzDu-UO6eg._PqujCUyMUqOkID80vJiDw`
key := []byte("thisisaverylongtextusedforhashing")

enc, err := jwt.ParseEncrypted(rawToken)
if err != nil {
	panic(err)
}

out := jwt.Claims{}
if err := enc.Claims(key, &out); err != nil {
	panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)

We are getting:
panic: square/go-jose: error in cryptographic primitive

PS: secret I pass to nextAuth used for the JWE generation: thisisaverylongtextusedforhashing

Raw JWE token that NextAuth outputs and which I want to validate in my golang server: eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..aiIqD7-cU8Hu92F8.Kx2k99cyLYJR1P0xK_1wUsVO521T7kYSKx-OEutVJcpzbX27hZH0kh2MlBLxQHdmc8q4uXglhjl4JE3nTp_c6nOjga-faHyxYqKrZGJFLlu9MC4JVUWyonX6doFq0gl3UX9ABtP2t35Qly-w1qKH8BdG9x4iB1YM-yvs1w-HpBbMFQR7U7X4oHWIh_YJQlWADesYq6da7A97GSSXs2Go6yb7SH5WWd7iQzDu-UO6eg._PqujCUyMUqOkID80vJiDw.

答案1

得分: 1

根据您的输入,我整理了一个回答,希望能帮助您解决问题。首先,我使用了版本2的gopkg.in/go-jose/go-jose.v2包,因为(根据我所看到的)算法A256GCM在最新版本的包中不完全兼容,最新版本应该是版本3。以下是相关的代码:

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/golang-jwt/jwt"
	jose_jwt "gopkg.in/go-jose/go-jose.v2"
)

type CustomClaims struct {
	Username string `json:"username"`
	Password string `json:"password"`
	jwt.StandardClaims
}

func main() {
	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		panic(err)
	}

	// 生成令牌
	token, err := generateToken()
	if err != nil {
		panic(err)
	}

	publicKey := &privateKey.PublicKey
	encrypter, err := jose_jwt.NewEncrypter(jose_jwt.A256GCM, jose_jwt.Recipient{
		Algorithm: jose_jwt.RSA_OAEP_256,
		Key:       publicKey,
	}, nil)
	if err != nil {
		panic(err)
	}

	plainText := []byte(token)
	object, err := encrypter.Encrypt(plainText)
	if err != nil {
		panic(err)
	}

	serialized := object.FullSerialize()

	object, err = jose_jwt.ParseEncrypted(serialized)
	if err != nil {
		panic(err)
	}

	decrypted, err := object.Decrypt(privateKey)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(decrypted))

	// 解析令牌
	claims, err := ValidateToken(string(decrypted))
	if err != nil {
		panic(err)
	}

	fmt.Println(len(claims))
}

在这里,我们首先生成一个私钥来加密令牌,然后通过其公钥解密它。为了简洁起见,我省略了用于生成和验证JWT令牌的代码。为了测试解决方案,我在生成的令牌中添加了两个自定义声明(usernamepassword,在CustomClaims结构体中定义)。然后,当我们解析令牌时,我们将能够获取它们的值。

如果有帮助,请告诉我!

英文:

Given your input, I put together a response that could help you with your issue. First, I used version 2 of the package gopkg.in/go-jose/go-jose.v2 because (from what I saw) the algorithm A256GCM is not fully compatible in the newest version of the package that should be version 3. Below you can find the relevant code:

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/golang-jwt/jwt"
	jose_jwt "gopkg.in/go-jose/go-jose.v2"
)

type CustomClaims struct {
	Username string `json:"username"`
	Password string `json:"password"`
	jwt.StandardClaims
}

func main() {
	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		panic(err)
	}

	// generate token
	token, err := generateToken()
	if err != nil {
		panic(err)
	}

	publicKey := &privateKey.PublicKey
	encrypter, err := jose_jwt.NewEncrypter(jose_jwt.A256GCM, jose_jwt.Recipient{
		Algorithm: jose_jwt.RSA_OAEP_256,
		Key:       publicKey,
	}, nil)
	if err != nil {
		panic(err)
	}

	plainText := []byte(token)
	object, err := encrypter.Encrypt(plainText)
	if err != nil {
		panic(err)
	}

	serialized := object.FullSerialize()

	object, err = jose_jwt.ParseEncrypted(serialized)
	if err != nil {
		panic(err)
	}

	decrypted, err := object.Decrypt(privateKey)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(decrypted))

	// parse token
	claims, err := ValidateToken(string(decrypted))
	if err != nil {
		panic(err)
	}

	fmt.Println(len(claims))
}

Here, we first generate a private key to encrypt the token and then decrypt it through its public key. I omitted the code used to generate and validate a JWT token for brevity. To test out the solution I added two custom claims to the generated token (username and password that are defined in the CustomClaims struct). Then, when we parse the token, we'll be able to retrieve their values.
Let me know if this helps you!

huangapple
  • 本文由 发表于 2022年11月28日 07:45:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/74594670.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定