英文:
Azure JWT verification in Go is not working
问题
我有一个Go HTTP服务器。我想使用Azure JWT令牌来保护我的路由。我能够生成令牌,但无法验证它。
这是我的做法:
package main
import (
"context"
"errors"
"fmt"
"github.com/dgrijalva/jwt-go"
"github.com/lestrrat-go/jwx/jwa"
"github.com/lestrrat-go/jwx/jwk"
njwt "github.com/lestrrat-go/jwx/jwt"
)
const token = "<access-token>"
const jwksURL = `https://login.microsoftonline.com/common/discovery/keys`
func main() {
set, _ := jwk.Fetch(context.TODO(), jwksURL)
// 验证set是否具有所需的kid
verify2(token, set)
token, err := verify(token, set)
// token, err := jwt.Parse(token, getKey)
if err != nil {
panic(err)
}
claims := token.Claims.(jwt.MapClaims)
for key, value := range claims {
fmt.Printf("%s\t%v\n", key, value)
}
}
func verify2(token string, keyset jwk.Set) {
btoken := []byte(token)
parsedToken, err := njwt.Parse(
btoken, //token is a []byte
njwt.WithKeySet(keyset),
njwt.WithValidate(true),
)
fmt.Printf("%v %v", parsedToken, err)
}
func verify(tokenString string, keySet jwk.Set) (*jwt.Token, error) {
tkn, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if token.Method.Alg() != jwa.RS256.String() {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
kid, ok := token.Header["kid"].(string)
if !ok {
return nil, errors.New("kid header not found")
}
keys, ok := keySet.LookupKeyID(kid)
if !ok {
return nil, fmt.Errorf("key %v not found", kid)
}
var raw interface{}
err := keys.Raw(&raw)
return raw, err
})
return tkn, err
}
verify2(..)
返回 <nil> failed to match any of the keys
,而
verify(..)
返回 crypto/rsa: verification error
我的JWT头部:
{
"typ": "JWT",
"nonce": "...",
"alg": "RS256",
"x5t": "-KI3Q9nNR7bRofxmeZoXqbHZGew",
"kid": "-KI3Q9nNR7bRofxmeZoXqbHZGew"
}
英文:
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:
package main
import (
"context"
"errors"
"fmt"
"github.com/dgrijalva/jwt-go"
"github.com/lestrrat-go/jwx/jwa"
"github.com/lestrrat-go/jwx/jwk"
njwt "github.com/lestrrat-go/jwx/jwt"
)
const token = "<access-token>"
const jwksURL = `https://login.microsoftonline.com/common/discovery/keys`
func main() {
set, _ := jwk.Fetch(context.TODO(), jwksURL)
// verified that set has required kid
verify2(token, set)
token, err := verify(token, set)
// token, err := jwt.Parse(token, getKey)
if err != nil {
panic(err)
}
claims := token.Claims.(jwt.MapClaims)
for key, value := range claims {
fmt.Printf("%s\t%v\n", key, value)
}
}
func verify2(token string, keyset jwk.Set) {
btoken := []byte(token)
parsedToken, err := njwt.Parse(
btoken, //token is a []byte
njwt.WithKeySet(keyset),
njwt.WithValidate(true),
)
fmt.Printf("%v %v", parsedToken, err)
}
func verify(tokenString string, keySet jwk.Set) (*jwt.Token, error) {
tkn, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if token.Method.Alg() != jwa.RS256.String() {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
kid, ok := token.Header["kid"].(string)
if !ok {
return nil, errors.New("kid header not found")
}
keys, ok := keySet.LookupKeyID(kid)
if !ok {
return nil, fmt.Errorf("key %v not found", kid)
}
var raw interface{}
err := keys.Raw(&raw)
return raw, err
})
return tkn, err
}
verify2(..)
gives <nil> failed to match any of the keys
and
verify(..)
gives crypto/rsa: verification error
my JWT header:
{
"typ": "JWT",
"nonce": "...",
"alg": "RS256",
"x5t": "-KI3Q9nNR7bRofxmeZoXqbHZGew",
"kid": "-KI3Q9nNR7bRofxmeZoXqbHZGew"
}
答案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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论