{"record":{"id":"85e88c239ecc4622","repo":"netbirdio/netbird","slug":"validate-access-token-failed-with-error-v","errorCode":null,"errorMessage":"validate access token failed with error: %v","messagePattern":"validate access token failed with error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/internal/auth/device_flow.go","lineNumber":304,"sourceCode":"\t\t\t\t\tlog.Infof(\"device flow: IdP requested slow_down, polling interval increased to %s\", interval)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\treturn TokenInfo{}, errors.New(tokenResponse.ErrorDescription)\n\t\t\t}\n\n\t\t\ttokenInfo := TokenInfo{\n\t\t\t\tAccessToken:  tokenResponse.AccessToken,\n\t\t\t\tTokenType:    tokenResponse.TokenType,\n\t\t\t\tRefreshToken: tokenResponse.RefreshToken,\n\t\t\t\tIDToken:      tokenResponse.IDToken,\n\t\t\t\tExpiresIn:    tokenResponse.ExpiresIn,\n\t\t\t\tUseIDToken:   d.providerConfig.UseIDToken,\n\t\t\t}\n\n\t\t\terr = validateTokenAudience(tokenInfo.GetTokenToUse(), d.providerConfig.Audience)\n\t\t\tif err != nil {\n\t\t\t\treturn TokenInfo{}, fmt.Errorf(\"validate access token failed with error: %v\", err)\n\t\t\t}\n\n\t\t\tlog.Infof(\"device flow: user authorization confirmed after %d polls in %s\", polls, time.Since(start).Round(time.Second))\n\t\t\treturn tokenInfo, err\n\t\t}\n\t}\n}\n","sourceCodeStart":286,"sourceCodeEnd":312,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/internal/auth/device_flow.go#L286-L312","documentation":"Raised by DeviceAuthorizationFlow.WaitToken after a token was successfully obtained, when validateTokenAudience rejects it (device_flow.go:302-305). validateTokenAudience (client/internal/auth/util.go:32) decodes the JWT payload without signature verification and requires the aud claim (string or array) to match providerConfig.Audience. A mismatch means the IdP issued a token for a different API/audience than the one NetBird management requested.","triggerScenarios":"The token's aud claim differs from the Audience configured in the NetBird IdP settings. Concrete producers: Azure AD returning an opaque or v1-audience access token when the API audience (api://...) is not registered/granted, Auth0 audience parameter not honored because the API is not configured, or management's configured Audience not matching the IdP application's identifier URI.","commonSituations":"Azure AD tenants where the NetBird app registration exposes api://<client-id> but admin consent or the audience grant is missing; Auth0 where the API identifier in NetBird management differs by a trailing slash or version from the API's identifier; switching an account's IdP configuration while old clients still hold the previous audience.","solutions":["Compare the aud claim of the returned token (decode the JWT payload) with the Audience configured in NetBird management - they must match exactly","On Azure AD, verify the app registration's 'Application ID URI' and that the NetBird service app has the user-scope consent for that API","If the IdP cannot issue JWT access tokens with the right audience, enable UseIDToken in the management IdP config so the (always JWT) ID token is validated and used instead","After changing the IdP config on management, restart the login flow; cached flow state can keep requesting the old audience"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Compare the token's aud claim with the configured audience before handing it on\nfunc tokenAudienceMatches(token, want string) bool {\n\tparts := strings.Split(token, \".\")\n\tif len(parts) != 3 {\n\t\treturn false\n\t}\n\tclaims, err := base64.RawURLEncoding.DecodeString(parts[1])\n\tif err != nil {\n\t\treturn false\n\t}\n\tvar c struct {\n\t\tAud any `json:\"aud\"`\n\t}\n\tif json.Unmarshal(claims, &c) != nil {\n\t\treturn false\n\t}\n\tswitch aud := c.Aud.(type) {\n\tcase string:\n\t\treturn aud == want\n\tcase []any:\n\t\tfor _, a := range aud {\n\t\t\tif s, ok := a.(string); ok && s == want {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}","typeGuard":null,"tryCatchPattern":"token, err := flow.WaitToken(ctx, info)\nif err != nil {\n\tif strings.Contains(err.Error(), \"validate access token failed\") {\n\t\t// configuration-level mismatch: point the administrator at the IdP audience settings\n\t}\n}","preventionTips":["Make the IdP API identifier (audience) in NetBird management exactly match the IdP application's identifier URI","For Azure AD, ensure the app registration exposes an Application ID URI and the consent is granted","Prefer enabling UseIDToken when the IdP cannot issue audience-carrying JWT access tokens"],"tags":["oauth2","jwt","audience","idp","azure-ad","configuration"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}