Golang: JWT: key is of invalid type
Всем привет!
Осваиваю JWT на golang
Есть вот такой тест
func TestJWTService_getAccess(t *testing.T) {
finish, service, _ := prepare(t)
defer finish()
access, err := service.getAccess("123")
assert.Nil(t, err)
assert.Len(t, *access, 164)
token, err := jwt.Parse(*access, func(token *jwt.Token) (interface{}, error) {
return token, nil
})
fmt.Println("access: ", access)
fmt.Println("err: ", err)
fmt.Println("token: ", token.Claims)
assert.Nil(t, err)
}
вот код самого метода
func (g *JWTService) getAccess(id string) (*string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodES256,
&claims.Claims{
ExpiresAt: time.Now().Add(15 * time.Minute).Unix(),
Id: id,
})
access, err := token.SignedString(g.TLSKey.Key)
if err != nil {
return nil, err
}
return &access, nil
}
вот ключ
-----BEGIN PRIVATE KEY-----
MHcCAQEEIAl3OVDPI+DZga26bSGBoIuYsXHYBMuBdhHqT/zdrYoFoAoGCCqGSM49
AwEHoUQDQgAESUiOTkfLNuzOGVolROj356z4pa585PcjLZnCqI8TtfZ8yqMinwbY
gFtba0RdYLuKTBZuKHycSxO8irgaegOJYQ==
-----END PRIVATE KEY-----
в строке fmt.Println("err: ", err) выдает
err: key is of invalid type
строка fmt.Println("access: ", jwtToken.Access) выдает
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTk4MjU1NTAsImp0aSI6IjEyMyJ9.lnrXSK-kBy9b6zp6BShsjgwrILNCOmXd3Se5CjWNNGu2aaajggBdZIQKpOqoYiBSbvk5d19thZV-H_vtNYh_8Q
строка fmt.Println("token: ", token.Claims) выдает
map[exp:1.69982555e+09 jti:123]
падает на строке assert.Nil(t, err) с ошибкой key is of invalid type
Не могу понять что я делаю не так и где ошибка?
Update: генерировал ключ эти кодом:
func TestGenKey(t *testing.T) {
// Генерируем новый ECDSA ключ
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
fmt.Println("Ошибка при генерации ключа:", err)
return
}
// Кодируем приватный ключ в формат PEM
privateKeyBytes, err := x509.MarshalECPrivateKey(privateKey)
if err != nil {
fmt.Println("Ошибка при кодировании приватного ключа:", err)
return
}
privateKeyPEM := &pem.Block{
Type: "EC PRIVATE KEY",
Bytes: privateKeyBytes,
}
// Создаем файл и сохраняем в него ключ
file, err := os.Create("../../../private.key")
if err != nil {
fmt.Println("Ошибка при создании файла:", err)
return
}
defer file.Close()
err = pem.Encode(file, privateKeyPEM)
if err != nil {
fmt.Println("Ошибка при кодировании PEM-блока:", err)
return
}
fmt.Println("Приватный ключ сохранен в файл private.key")
}
Ответы (1 шт):
Сорри, я не сразу понял, на какой из ключей у вас ругается jwt.
Функция-параметр для jwt.Parse должна возвращать публичный ключ, соответствующий приватному, который использовался для создания токена. Эта информация должна храниться где-то отдельно от токена. Например, в базе данных сервера, который сгенерировал токен.
В вашем случае нужно возвращать публичный ключ
token, err := jwt.Parse(*access, func(token *jwt.Token) (interface{}, error) {
return &service.TLSKey.Key.PublicKey, nil
})
Ваш пример был неполон, я его упростил:
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/pem"
"fmt"
"os"
"time"
"github.com/golang-jwt/jwt"
)
type JWTService struct {
TLSKey *ecdsa.PrivateKey
}
func main() {
service := &JWTService{
TLSKey: TestGenKeyMust(),
}
access, err := service.getAccess("123")
if err != nil {
panic(err)
}
token, err := jwt.Parse(access, func(token *jwt.Token) (interface{}, error) {
return &service.TLSKey.PublicKey, nil
})
if err != nil {
panic(err)
}
fmt.Println("access: ", access)
fmt.Println("err: ", err)
fmt.Println("token: ", token.Claims)
}
func (g *JWTService) getAccess(id string) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodES256,
&jwt.StandardClaims{
ExpiresAt: time.Now().Add(15 * time.Minute).Unix(),
Id: id,
})
access, err := token.SignedString(g.TLSKey)
if err != nil {
return "", err
}
return access, nil
}
func TestGenKeyMust() *ecdsa.PrivateKey {
key, err := TestGenKey()
if err != nil {
panic(err)
}
return key
}
func TestGenKey() (*ecdsa.PrivateKey, error) {
// Генерируем новый ECDSA ключ
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
fmt.Println("Ошибка при генерации ключа:", err)
return nil, err
}
// Кодируем приватный ключ в формат PEM
privateKeyBytes, err := x509.MarshalECPrivateKey(privateKey)
if err != nil {
fmt.Println("Ошибка при кодировании приватного ключа:", err)
return nil, err
}
privateKeyPEM := &pem.Block{
Type: "EC PRIVATE KEY",
Bytes: privateKeyBytes,
}
// Создаем файл и сохраняем в него ключ
// file, err := os.Create("private.key")
file, err := os.Stdout, nil
if err != nil {
fmt.Println("Ошибка при создании файла:", err)
return nil, err
}
// defer file.Close()
err = pem.Encode(file, privateKeyPEM)
if err != nil {
fmt.Println("Ошибка при кодировании PEM-блока:", err)
return nil, err
}
fmt.Println("Приватный ключ сохранен в файл private.key")
return privateKey, nil
}
Запустить: https://go.dev/play/p/LxONs3Pyw2t
Когда jwt.Parse получает правильный ключ, он верифицирует токен без ошибки.
token, err := jwt.Parse(access, func(token *jwt.Token) (interface{}, error) {
return &service.TLSKey.PublicKey, nil
})