skip to Main Content

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("%st%vn", 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"
}

3

Answers


  1. Chosen as BEST ANSWER

    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


  2. 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)

    Login or Signup to reply.
  3. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search