Azure JWT在Go中的验证不起作用

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

Azure JWT verification in Go is not working

问题

我有一个Go HTTP服务器。我想使用Azure JWT令牌来保护我的路由。我能够生成令牌,但无法验证它。

这是我的做法:

  1. package main
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "github.com/dgrijalva/jwt-go"
  7. "github.com/lestrrat-go/jwx/jwa"
  8. "github.com/lestrrat-go/jwx/jwk"
  9. njwt "github.com/lestrrat-go/jwx/jwt"
  10. )
  11. const token = "<access-token>"
  12. const jwksURL = `https://login.microsoftonline.com/common/discovery/keys`
  13. func main() {
  14. set, _ := jwk.Fetch(context.TODO(), jwksURL)
  15. // 验证set是否具有所需的kid
  16. verify2(token, set)
  17. token, err := verify(token, set)
  18. // token, err := jwt.Parse(token, getKey)
  19. if err != nil {
  20. panic(err)
  21. }
  22. claims := token.Claims.(jwt.MapClaims)
  23. for key, value := range claims {
  24. fmt.Printf("%s\t%v\n", key, value)
  25. }
  26. }
  27. func verify2(token string, keyset jwk.Set) {
  28. btoken := []byte(token)
  29. parsedToken, err := njwt.Parse(
  30. btoken, //token is a []byte
  31. njwt.WithKeySet(keyset),
  32. njwt.WithValidate(true),
  33. )
  34. fmt.Printf("%v %v", parsedToken, err)
  35. }
  36. func verify(tokenString string, keySet jwk.Set) (*jwt.Token, error) {
  37. tkn, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
  38. if token.Method.Alg() != jwa.RS256.String() {
  39. return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
  40. }
  41. kid, ok := token.Header["kid"].(string)
  42. if !ok {
  43. return nil, errors.New("kid header not found")
  44. }
  45. keys, ok := keySet.LookupKeyID(kid)
  46. if !ok {
  47. return nil, fmt.Errorf("key %v not found", kid)
  48. }
  49. var raw interface{}
  50. err := keys.Raw(&raw)
  51. return raw, err
  52. })
  53. return tkn, err
  54. }

verify2(..) 返回 &lt;nil&gt; failed to match any of the keys,而
verify(..) 返回 crypto/rsa: verification error

我的JWT头部:

  1. {
  2. "typ": "JWT",
  3. "nonce": "...",
  4. "alg": "RS256",
  5. "x5t": "-KI3Q9nNR7bRofxmeZoXqbHZGew",
  6. "kid": "-KI3Q9nNR7bRofxmeZoXqbHZGew"
  7. }
英文:

I have a Go HTTP Server. I want to protect my routes using Azure JWT Token. I am able to generate the token but I am not able to verify it.

This is how I am doing it:

  1. package main
  2. import (
  3. &quot;context&quot;
  4. &quot;errors&quot;
  5. &quot;fmt&quot;
  6. &quot;github.com/dgrijalva/jwt-go&quot;
  7. &quot;github.com/lestrrat-go/jwx/jwa&quot;
  8. &quot;github.com/lestrrat-go/jwx/jwk&quot;
  9. njwt &quot;github.com/lestrrat-go/jwx/jwt&quot;
  10. )
  11. const token = &quot;&lt;access-token&gt;&quot;
  12. const jwksURL = `https://login.microsoftonline.com/common/discovery/keys`
  13. func main() {
  14. set, _ := jwk.Fetch(context.TODO(), jwksURL)
  15. // verified that set has required kid
  16. verify2(token, set)
  17. token, err := verify(token, set)
  18. // token, err := jwt.Parse(token, getKey)
  19. if err != nil {
  20. panic(err)
  21. }
  22. claims := token.Claims.(jwt.MapClaims)
  23. for key, value := range claims {
  24. fmt.Printf(&quot;%s\t%v\n&quot;, key, value)
  25. }
  26. }
  27. func verify2(token string, keyset jwk.Set) {
  28. btoken := []byte(token)
  29. parsedToken, err := njwt.Parse(
  30. btoken, //token is a []byte
  31. njwt.WithKeySet(keyset),
  32. njwt.WithValidate(true),
  33. )
  34. fmt.Printf(&quot;%v %v&quot;, parsedToken, err)
  35. }
  36. func verify(tokenString string, keySet jwk.Set) (*jwt.Token, error) {
  37. tkn, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
  38. if token.Method.Alg() != jwa.RS256.String() {
  39. return nil, fmt.Errorf(&quot;unexpected signing method: %v&quot;, token.Header[&quot;alg&quot;])
  40. }
  41. kid, ok := token.Header[&quot;kid&quot;].(string)
  42. if !ok {
  43. return nil, errors.New(&quot;kid header not found&quot;)
  44. }
  45. keys, ok := keySet.LookupKeyID(kid)
  46. if !ok {
  47. return nil, fmt.Errorf(&quot;key %v not found&quot;, kid)
  48. }
  49. var raw interface{}
  50. err := keys.Raw(&amp;raw)
  51. return raw, err
  52. })
  53. return tkn, err
  54. }

verify2(..) gives &lt;nil&gt; failed to match any of the keys and
verify(..) gives crypto/rsa: verification error

my JWT header:

  1. {
  2. &quot;typ&quot;: &quot;JWT&quot;,
  3. &quot;nonce&quot;: &quot;...&quot;,
  4. &quot;alg&quot;: &quot;RS256&quot;,
  5. &quot;x5t&quot;: &quot;-KI3Q9nNR7bRofxmeZoXqbHZGew&quot;,
  6. &quot;kid&quot;: &quot;-KI3Q9nNR7bRofxmeZoXqbHZGew&quot;
  7. }

答案1

得分: 3

你正在使用错误类型的Azure AD访问令牌。带有JWT头部中的nonce的令牌不是用于验证你自己的API的,而是用于Microsoft自己的API。

你需要公开一个API范围来解决这个问题,之后你将获得一个JWT头部中没有nonce的访问令牌。我的博客文章中有一些相关的进一步信息。

英文:

You are using the wrong type of Azure AD access token. Those with a nonce in the JWT header are not designed to be validated by your own APIs - they are intended for Microsoft's own APIs.

You need to expose an API scope to fix this, after which you will get an access token without a nonce in the JWT header. My blog post has some further related info.

答案2

得分: 2

我在另一种语言中遇到了类似的问题。我的手动令牌验证对于某些令牌有效。我注意到,当JWT头部中有"nonce"声明时,验证失败,而当没有该声明时,其他令牌可以正常工作。你可以尝试使用另一个没有"nonce"的令牌来检查一下吗?这样可以缩小问题的范围。

英文:

I have similar problem in another language. My manual token verification works for some tokens. It came to my attention that when I have the "nonce" claim on the JWT header, validation fails, for other tokens when I don't have it, it works. May you please check with another token where you don't have the "nonce"? (just to narrow down the problem)

答案3

得分: 0

每当我们添加一个范围来访问Microsoft Graph API时,Azure会返回一个只能由Microsoft Graph API验证的访问令牌。

替代方法1:

  • 在后端签署自己的JWT以授权前端请求
  • access_token存储在某个地方

替代方法2:

  • 调用Graph API并使用声明签署一个JWT
  • 在前端和后端之间验证和使用JWT

**注意:**不要在声明中存储敏感信息

Microsoft的OAuth令牌所有者对此发表了评论:https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609#issuecomment-524434987

了解更多关于Azure OIDC的信息:https://xsreality.medium.com/making-azure-ad-oidc-compliant-5734b70c43ff

英文:

Anytime we add a scope to access Microsoft graph API. Azure sends back an access_token that can only be verified by Microsoft graph API.

Alternative approach 1:

  • Sign my own JWT to authorize my front-end requests in the back-end
  • Store the access_token somewhere

Alternative approach 2:

  • Make a call to graph API and sign a JWT with the claims
  • Verify and use the JWT between your FE and BE

NOTE: Do not do store sensitive information in the claims

Microsoft's OAuth tokens owner comment about this: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609#issuecomment-524434987

Learn more about Azure OIDC: https://xsreality.medium.com/making-azure-ad-oidc-compliant-5734b70c43ff

huangapple
  • 本文由 发表于 2023年4月13日 12:19:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76001593.html
匿名

发表评论

匿名网友

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

确定