Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Microsoft nonce and state doesn't match #366

Open
onattech opened this issue Feb 12, 2023 · 1 comment
Open

Microsoft nonce and state doesn't match #366

onattech opened this issue Feb 12, 2023 · 1 comment

Comments

@onattech
Copy link

onattech commented Feb 12, 2023

Hi,
I am trying to figure out open-id connect with Microsoft. I am getting nonce and state doesn't match errors. Cookie in the browser doesn't seem to update. If I remove those checks, it seems to work. Can someone point out what am I doing wrong or maybe give a working example for Microsoft. Here's my code below
Added comments to the lines that I changed from the original example.

func main() {
	godotenv.Load()
	clientID := os.Getenv("MICROSOFT_OAUTH2_CLIENT_ID")         // <==
	clientSecret := os.Getenv("MICROSOFT_OAUTH2_CLIENT_SECRET") // <==

	ctx := context.Background()

	discoveryBaseURL := "https://login.microsoftonline.com/common/v2.0"                        // <==
	issuerURL := "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a500b66dad/v2.0" // <==

	ctx = oidc.InsecureIssuerURLContext(ctx, issuerURL) // <==

	// Provider will be discovered with the discoveryBaseURL, but use issuerURL
	// for future issuer validation.
	provider, err := oidc.NewProvider(ctx, discoveryBaseURL) // <==

	if err != nil {
		log.Fatal(err)
	}
	oidcConfig := &oidc.Config{
		ClientID: clientID,
	}
	verifier := provider.Verifier(oidcConfig)

	config := oauth2.Config{
		ClientID:     clientID,
		ClientSecret: clientSecret,
		Endpoint:     provider.Endpoint(),
		RedirectURL:  "http://localhost:5556/auth/microsoft/callback", // <==
		Scopes:       []string{oidc.ScopeOpenID, "profile", "email"},
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		state, err := randString(16)
		if err != nil {
			http.Error(w, "Internal error", http.StatusInternalServerError)
			return
		}
		nonce, err := randString(16)
		if err != nil {
			http.Error(w, "Internal error", http.StatusInternalServerError)
			return
		}
		setCallbackCookie(w, r, "state", state)
		setCallbackCookie(w, r, "nonce", nonce)

		http.Redirect(w, r, config.AuthCodeURL(state, oidc.Nonce(nonce)), http.StatusFound)
	})

	http.HandleFunc("/auth/microsoft/callback", func(w http.ResponseWriter, r *http.Request) { // <==
		state, err := r.Cookie("state")
		if err != nil {
			http.Error(w, "state not found", http.StatusBadRequest)
			return
		}
		if r.URL.Query().Get("state") != state.Value {
			http.Error(w, "state did not match", http.StatusBadRequest)
			return
		}

		oauth2Token, err := config.Exchange(ctx, r.URL.Query().Get("code"))
		if err != nil {
			http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError)
			return
		}
		rawIDToken, ok := oauth2Token.Extra("id_token").(string)
		if !ok {
			http.Error(w, "No id_token field in oauth2 token.", http.StatusInternalServerError)
			return
		}
		idToken, err := verifier.Verify(ctx, rawIDToken)
		if err != nil {
			http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError)
			return
		}

		nonce, err := r.Cookie("nonce")
		if err != nil {
			http.Error(w, "nonce not found", http.StatusBadRequest)
			return
		}
		if idToken.Nonce != nonce.Value {
			http.Error(w, "nonce did not match", http.StatusBadRequest)
			return
		}

		oauth2Token.AccessToken = "*REDACTED*"

		resp := struct {
			OAuth2Token   *oauth2.Token
			IDTokenClaims *json.RawMessage // ID Token payload is just JSON.
		}{oauth2Token, new(json.RawMessage)}

		if err := idToken.Claims(&resp.IDTokenClaims); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data, err := json.MarshalIndent(resp, "", "    ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(data)
	})

	log.Printf("listening on http://%s/", "127.0.0.1:5556")
	log.Fatal(http.ListenAndServe("localhost:5556", nil)) // <===
}
@onattech onattech changed the title Microsoft cookie and state doesn't match Microsoft nonce and state doesn't match Feb 12, 2023
@richie-tt
Copy link

I stuck with the same problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants