端点Google ID JWT和Golang oauth2:有id_token,需要access_token吗?

时间:2017-10-16 07:46:23

标签: go oauth-2.0 google-cloud-endpoints

我在端点后面有一个应用程序引擎应用程序,但我无法遵循有关添加身份验证的文档。我的偏好是允许项目中的服务帐户通过,然后执行更精细的应用程序端授权。

在我的情况下,大多数客户将在GCP之外并且将是自动程序而不是人,所以我使用JSON密钥文件认为这是要走的路(如果我错了请纠正我)。我也不想重新部署应用程序以更改用户配置,因此我按照此处的文档中的“GOOGLE ID JWT”信息进行操作:

https://cloud.google.com/endpoints/docs/openapi/service-to-service-auth

这是我招摇的JSON的安全部分:

  "securityDefinitions": {
    "api_key": {
      "type": "apiKey",
      "name": "key",
      "in": "query"
    },
    "google_id_token": {
      "authorizationUrl": "",
      "flow": "implicit",
      "type": "oauth2",
      "x-google-issuer": "https://accounts.google.com"
    }
  },
  "security": [
    {
      "api_key": [],
      "google_id_token": []
    }
  ]

这部署正常,但我很难从客户端做什么来使用服务帐户JSON。

在Go中,根据我对oauth2 / google文档的理解,我使用以下内容:

package main

import (
    "context"
    "fmt"
    "io/ioutil"
    "log"
    "os"

    "golang.org/x/oauth2/google"
)

func main() {
    ctx := context.Background()
    apiKey := os.Getenv("API_KEY")
    basePath := "https://SERVICE_NAME-dot-PROJECT_NAME.appspot.com" // changed for privacy

    creds, _ := google.FindDefaultCredentials(ctx)
    jwt, _ := google.JWTConfigFromJSON(creds.JSON, basePath)

    client := jwt.Client(ctx)
    res, _ := client.Get(fmt.Sprintf("%s/REQUEST_PATH?key=%s", basePath, apiKey)) // changed for privacy

    body, _ := ioutil.ReadAll(res.Body)
    log.Printf("### http status: %d %s", res.StatusCode, res.Status)
    log.Printf("### http body: %s", body)
}

为了简洁,我删除了此代码粘贴的错误检查,运行时没有错误。结果如下:

2017/10/16 07:32:38 ### http status: 401 401 Unauthorized
2017/10/16 07:32:38 ### http body: {
 "code": 16,
 "message": "JWT validation failed: Missing or invalid credentials",
 "details": [
  {
   "@type": "type.googleapis.com/google.rpc.DebugInfo",
   "stackEntries": [],
   "detail": "auth"
  }
 ]
}

在检查正在发生的事情的内部情况时,例如拨打jwt.TokenSource(ctx).Token(),我发现Google正在返回id_token,但没有access_token(通过添加一些调试日志来发现jwt包):

2017/10/16 07:38:47 ### oauth2/jwt -> tokenURL: https://accounts.google.com/o/oauth2/token, form: url.Values{"grant_type":[]string{"urn:ietf:params:oauth:grant-type:jwt-bearer"}, "assertion":[]string{"...cut..."}}
2017/10/16 07:38:47 ### oauth2/jwt <- response: {
  "id_token" : "...cut..."
}
2017/10/16 07:38:47 ### oauth2/jwt <- token: &oauth2.Token{AccessToken:"", TokenType:"", RefreshToken:"", Expiry:time.Time{wall:0x0, ext:63643740079, loc:(*time.Location)(0x1424160)}, raw:map[string]interface {}{"id_token":"...cut..."}}

因此,当oauth2 HTTP传输尝试添加auth标头(与上面的AccessToken字段绑定)时,会产生类似Authorization: Bearer的字符串,从而导致结果失败。

我觉得我在这里错过了一个步骤,这在文档中并不明显。

感谢您的时间。

1 个答案:

答案 0 :(得分:1)

oauth客户端应该返回Iterator<String> itr = s.iterator(); while(itr.hasNext()){ Permission p = itr.next(); } 而不是id_token。您使用的是access_token,而不是JWTConfigFromJSON,这是正确的。我认为ConfigFromJSON的第二个参数是不正确的,您应该指定范围。在这种情况下,请尝试JWTConfigFromJSON而不是"email"