英文:
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获取,大致的过程如下:
- 将"github.com/golang-jwt/jwt/v4"添加到您的导入中。
- 创建一组声明,其中可以包括RegisteredClaims类型和您可能需要的任何自定义声明。
- 使用jwt.NewWithClaims()创建令牌-您需要提供适当的签名方法。我主要使用RS256。
- 使用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:
- Add "github.com/golang-jwt/jwt/v4" to your imports.
- Create a set of claims, which can include the RegisteredClaims type and any custom claims you may need.
- Create the token with jwt.NewWithClaims() - you'll need to provide the appropriate signing method. I've primarily used RS256.
- 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 theiat
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 "github.com/golang-jwt/jwt/v5"
func main() {
pemFilePath := "private-key.pem" // replace
appId := "<app-id>" // replace
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)
}
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 theiat
. It would be better to.Add()
from aniat
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论