Generate a JWT from GitHub App PEM private key in Go

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

Generate a JWT from GitHub App PEM private key in Go

问题

我正在尝试使用GitHub App,并且需要生成一个JWT进行身份验证(https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#generating-a-private-key)。
我正在尝试在Go中使用Goland来完成这个操作。
请问如何在Go中使用PEM私钥生成JWT?

英文:

I'm trying to use GitHub App and I need to generate a JWT for authenticating (https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#generating-a-private-key)
I'm trying to do that using Goland.
How can I generate a JWT from PEM private key in Go??

答案1

得分: 6

jwt-go库具有您所需的所有工具,并且文档相当完善。您可以在https://github.com/golang-jwt/jwt找到它。

假设您了解JWT是什么以及它们的结构,并且可以将PEM密钥作为[]byte获取,大致的过程如下:

  1. 将"github.com/golang-jwt/jwt/v4"添加到您的导入中。
  2. 创建一组声明,其中可以包括RegisteredClaims类型和您可能需要的任何自定义声明。
  3. 使用jwt.NewWithClaims()创建令牌-您需要提供适当的签名方法。我主要使用RS256。
  4. 使用token.SignedString()从令牌创建JWT字符串。

实际上,它看起来像这样:

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

type MyCustomClaims struct {
    *jwt.RegisteredClaims
    FooClaim int
    BarClaim string
}

func CreateJWT(pemKey []byte) string {
    // 过期时间为60分钟
    expiration := time.Now().Add(time.Second * 3600)

    claims := MyCustomClaims{
        RegisteredClaims: &jwt.RegisteredClaims{
            Issuer:    "Example Code Inc.",
            ExpiresAt: jwt.NewNumericDate(expiration),
            Subject:   "JWT Creation",
        },
        FooClaim: 123,
        BarClaim: "bar",
    }

    token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)

    privateKey, _ := jwt.ParseRSAPrivateKeyFromPEM(pemKey)

    myJWT, _ := token.SignedString(privateKey)

    return myJWT
}
英文:

The jwt-go library has all the tools you need, and is fairly well documented. You can find it at https://github.com/golang-jwt/jwt.

Assuming you understand what JWTs are and how they're structured, and that you can get that PEM key as a []byte, the process is roughly:

  1. Add "github.com/golang-jwt/jwt/v4" to your imports.
  2. Create a set of claims, which can include the RegisteredClaims type and any custom claims you may need.
  3. Create the token with jwt.NewWithClaims() - you'll need to provide the appropriate signing method. I've primarily used RS256.
  4. Create the JWT string from the token with token.SignedString().

In practice, it will look something like this:

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

type MyCustomClaims struct {
    *jwt.RegisteredClaims
    FooClaim int
    BarClaim string
}

func CreateJWT(pemKey []byte) string {
    // expires in 60 minutes
    expiration := time.Now().Add(time.Second * 3600)

    claims := MyCustomClaims{
        RegisteredClaims: &jwt.RegisteredClaims{
            Issuer:    "Example Code Inc.",
            ExpiresAt: jwt.NewNumericDate(expiration),
            Subject:   "JWT Creation",
        },
        FooClaim: 123,
        BarClaim: "bar",
    }

    token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)

    privateKey, _ := jwt.ParseRSAPrivateKeyFromPEM(pemKey)

    myJWT, _ := jwt.SignedString(privateKey)

    return myJWT
}

答案2

得分: 1

成功创建GitHub应用程序JWT令牌的Go代码如下所示,该令牌是从私有权限文件中生成的,需要以下JWT声明:

  • iat:令牌的“发行时间”(减去60秒以解决时钟浮动)
  • exp:令牌的到期时间(不超过iat后的10分钟)
  • iss:GitHub应用程序的App ID(注意:这不是应用程序的客户端ID)。

完成上述步骤后,可以创建一个新的JWT令牌,用于与GitHub API进行通信。

package main

import "github.com/golang-jwt/jwt/v5"

func main() {
    pemFilePath := "private-key.pem" // 替换为实际路径

    appId := "<app-id>" // 替换为实际App ID
    now := time.Now()

    token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
        "iat": jwt.NewNumericDate(now.Add(-time.Minute)),
        "exp": jwt.NewNumericDate(now.Add(5 * time.Minute)),
        "iss": appId,
    })

    pemKey, _ := ioutil.ReadFile(pemFilePath)

    privateKey, _ := jwt.ParseRSAPrivateKeyFromPEM(pemKey)

    tokenString, err := token.SignedString(privateKey)
    if err != nil {
        panic(err)
    }
    
    fmt.Println(tokenString)
}

在上面的示例中,我们使用ioutil.ReadFile读取pem文件的字节(由GitHub提供)。然后解析字节并最终创建一个带有签名的字符串。

注意:

  • 示例中将exp设置为5分钟。它不能超过iat后的10分钟。最好从iat值开始使用.Add()来确保时间正确。
  • now.Add(-time.Minute)实际上是将当前时间减去一分钟。

希望对你有所帮助。

英文:

To successfully create a github app jwt token from a private permissions file in Go, the following jwt claims are required:

  • iat: the "issued at" date of the token (minus 60 seconds for clock float)
  • exp: the expiry date of the token (no more than 10 minutes from the iat
  • iss: the App ID of the Github app (Note: This is not the client id of the app).

Once this is in place, a new jwt token can be created which can be used to communicate with the github api.

package main

import &quot;github.com/golang-jwt/jwt/v5&quot;

func main() {
    pemFilePath := &quot;private-key.pem&quot; // replace

    appId := &quot;&lt;app-id&gt;&quot; // replace
    now := time.Now()

    token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
        &quot;iat&quot;: jwt.NewNumericDate(now.Add(-time.Minute)),
        &quot;exp&quot;: jwt.NewNumericDate(now.Add(5 * time.Minute)),
        &quot;iss&quot;: appID,
    })

    pemKey, _ := ioutil.ReadFile(pemFilePath)

    privateKey, _ := jwt.ParseRSAPrivateKeyFromPEM(pemKey)

    tokenString, err := token.SignedString(privateKey)
    if err != nil {
        panic(err)
    }
    
    fmt.Println(tokenString)
}

In the example above, we use ioutil.ReadFile to read the bytes of the pem file (this is supplied by Github). When then parse the bytes and finally create a signed string with it.

Notes:

  • Example shows exp set to 5 minutes. It can be no longer than 10 minutes from the iat. It would be better to .Add() from an iat value to ensure it is the correct time.
  • now.Add(-time.Minute) will essentially subtract the current time by a minute

Hope this helps.

答案3

得分: 0

我建议阅读这个代码库的代码:

https://github.com/bradleyfalzon/ghinstallation

我不知道为什么,但是上面@JesseB的答案中的代码对我来说不起作用 - 它总是抛出401 Unauthorized的错误。尽管这个代码库内部使用了golang-jwt包。

英文:

I suggest reading code from this repository:

https://github.com/bradleyfalzon/ghinstallation

I don't know why, but the code in the answer from @JesseB above didn't work for me - it always throws: 401 Unauthorized. Although this repository does use golang-jwt package internally

huangapple
  • 本文由 发表于 2022年8月18日 15:31:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/73399076.html
匿名

发表评论

匿名网友

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

确定