Golang Oauth2服务帐户返回空的刷新令牌字符串。

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

Golang Oauth2 Service account returns empty refresh token string

问题

我在尝试使用google/Oauth2包进行身份验证时遇到了问题,使用服务器对服务器身份验证通过服务帐号进行身份验证时,Google会返回一个带有空刷新令牌字符串的令牌结构,并且令牌在1小时后过期,由于我没有刷新令牌,所以无法刷新令牌。
以下是我使用的代码片段:

/*
import(
    "github.com/google/go-containerregistry/pkg/authn"
	gcr "github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1/remote"
)

*/
data, err := ioutil.ReadFile(fmt.Sprintf("%s/%s", path, serviceAccountFilePath))
if err != nil {
   log.Fatalf("Failed to read GCP service account key file: %s", err)
}
ctx := context.Background()
fmt.Println(scopes)
creds, err := google.CredentialsFromJSON(ctx, data, scopes...)

if err != nil {
   log.Fatalf("Failed to load GCP service account credentials: %s", err)

}
t, _ := creds.TokenSource.Token()
fmt.Println(t.Expiry.Sub(time.Now()).String(), t.RefreshToken, ">>>")

r, err := gcr.NewRegistry("https://gcr.io")
if err != nil {
 log.Fatalf("failed to ping registry: %s", err)
}
authToken := authn.FromConfig(authn.AuthConfig{
	RegistryToken: t.AccessToken,
})

repo, err := gcr.NewRepository(fmt.Sprintf("%s/%s", urlPrefix, imageName))
repo.Registry = r
list, err := remote.List(repo, remote.WithAuth(authToken))

Golang Oauth2服务帐户返回空的刷新令牌字符串。

我尝试了不同的方法来使用服务帐号进行身份验证,例如使用配置和JWT,但仍然得到了相同的结果。

英文:

I'm having a problem with the google/Oauth2 package when attempting to authenticate through the service account using a server to server authentication. Google responds with a token struct with an empty refresh token string, and the token expires in 1h, which I can't refresh as I don't have a refresh token.
Here is the code snippet I'm using:

/*
import(
    "github.com/google/go-containerregistry/pkg/authn"
	gcr "github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1/remote"
)

*/
data, err := ioutil.ReadFile(fmt.Sprintf("%s/%s", path, serviceAccountFilePath))
if err != nil {
   log.Fatalf("Failed to read GCP service account key file: %s", err)
}
ctx := context.Background()
fmt.Println(scopes)
creds, err := google.CredentialsFromJSON(ctx, data, scopes...)

if err != nil {
   log.Fatalf("Failed to load GCP service account credentials: %s", err)

}
t, _ := creds.TokenSource.Token()
fmt.Println(t.Expiry.Sub(time.Now()).String(), t.RefreshToken, ">>>")

r, err := gcr.NewRegistry("https://gcr.io")
if err != nil {
 log.Fatalf("failed to ping registry: %s", err)
}
authToken := authn.FromConfig(authn.AuthConfig{
	RegistryToken: t.AccessToken,
})

repo, err := gcr.NewRepository(fmt.Sprintf("%s/%s", urlPrefix, imageName))
repo.Registry = r
list, err := remote.List(repo, remote.WithAuth(authToken))

Golang Oauth2服务帐户返回空的刷新令牌字符串。

I tried different ways while using the service account for authentication, such as the config and JWT but I still got the same result.

答案1

得分: 1

服务账号不需要/使用刷新令牌。

刷新令牌用于标准的OAuth2授权的离线访问。如果用户处于离线状态,应用程序可以使用刷新令牌获取新的访问令牌,并代表用户发出请求。

对于服务账号,它们已经预授权并具有访问其数据的权限。一次请求应该返回一个访问令牌,一旦该访问令牌在一个小时后过期,只需再次进行授权请求以获取新的访问令牌。

在服务账号的情况下,刷新令牌是不必要的。当访问令牌过期时,只需再次运行授权代码以获取新的访问令牌。这样可以省去一个步骤。

英文:

Service accounts don't need / use refresh tokens.

Refresh tokens are used for offline access by standard Oauth2 authorization. If the user is offline then the application can use the refresh tokens to get an new access token and make requests on behalf of the user.

With service accounts they are already preauthorized and have access to the data they have. A request should return an access token once that access token expires after an hour you just make a new authorization request to get a new access token.

Refresh tokens are unnecessary in the case of service accounts. When the access token expires just run your auth code again to get a new one. Its saving you a step.

答案2

得分: 1

感谢@DalmTo的提示,我解决了这个问题。

所以解决这个问题的方法是不要使用google.CredentialsFromJSON()函数之外的凭据,该函数将返回令牌源,而不会在将服务帐号传递给该函数的情况下刷新令牌,这意味着当令牌再次过期时,您无法刷新令牌。此外,我尝试了预期并重新进行身份验证以生成新令牌,但对我来说没有起作用(不知道为什么)。

所以我不得不通过以下函数将服务帐号的JSON转换为JWT

scopes := []string{"https://www.googleapis.com/auth/cloud-platform"}
tokenSource, err := google.JWTAccessTokenSourceWithScope(serviceAccountFileBytes, scopes...)

这个函数之所以有效,是因为它通过服务帐号的属性(如客户端电子邮件、client_id和private_key)在内部创建JWT令牌,GCP允许我们创建本地JWT令牌并对其进行编码。

英文:

Thanks to @DalmTo's hints, I solved the problem.

So the fix for the such problem was by not using the credentials out of google.CredentialsFromJSON() func will return the token source without refreshing the token in case of passing the service account to that function, which means that you can't refresh your token when it expires again later. Also, anticipating and re-authenticating to generate a new token didn't work for me (no clue why).

So I had to convert the JSON of the service account into JWT through this func instead

scopes := []string{"https://www.googleapis.com/auth/cloud-platform"}
tokenSource, err := google.JWTAccessTokenSourceWithScope(serviceAccountFileBytes, scopes...)

The reason that this one works, is because it creates the JWT token internally through the service_account's properties such as client email and client_id and private_key as GCP allows us to create our local JWT tokens and encode them.

huangapple
  • 本文由 发表于 2023年1月1日 22:19:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/74975133.html
匿名

发表评论

匿名网友

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

确定