{"record":{"id":"8e8d55a2b69602a2","repo":"netbirdio/netbird","slug":"required-token-field-audience-is-absent","errorCode":null,"errorMessage":"required token field audience is absent","messagePattern":"required token field audience is absent","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/internal/auth/util.go","lineNumber":54,"sourceCode":"\n\tparts := strings.Split(token, \".\")\n\tif len(parts) != 3 {\n\t\treturn fmt.Errorf(\"token is not a well-formed JWT\")\n\t}\n\n\tclaimsString, err := base64.RawURLEncoding.DecodeString(parts[1])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tclaims := Claims{}\n\terr = json.Unmarshal(claimsString, &claims)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif claims.Audience == nil {\n\t\treturn fmt.Errorf(\"required token field audience is absent\")\n\t}\n\n\t// Audience claim of JWT can be a string or an array of strings\n\tswitch aud := claims.Audience.(type) {\n\tcase string:\n\t\tif aud == audience {\n\t\t\treturn nil\n\t\t}\n\tcase []interface{}:\n\t\tfor _, audItem := range aud {\n\t\t\tif audStr, ok := audItem.(string); ok && audStr == audience {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fmt.Errorf(\"invalid JWT token audience field\")\n}","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/internal/auth/util.go#L36-L72","documentation":"The token was a structurally valid JWT and its payload parsed as JSON, but the aud claim is absent (claims.Audience == nil). The check requires an audience because the whole point is confirming the token targets this deployment; an aud-less token cannot be matched against the configured Audience or the ClientID fallback.","triggerScenarios":"The IdP mints tokens without an aud claim: the authorization request carried no audience/resource parameter, the API registration in the IdP has no identifier configured, or a custom claims policy strips aud.","commonSituations":"Keycloak client config with no audience mapper in the client scope; Auth0 API identifier not passed as the audience parameter; Azure AD app registration missing the API/exposed scope so tokens come out without the resource audience.","solutions":["Configure the IdP to include the audience: add an audience mapper/claim (Keycloak), set the API identifier as audience (Auth0), or expose an API/scope so the token carries the resource aud (Azure AD).","Ensure the audience parameter NetBird sends in the authorization request matches an audience the IdP actually supports - the flow passes it via oauth2.SetAuthURLParam(\"audience\", ...).","Re-login after fixing the IdP so a freshly minted token is checked.","If the provider truly cannot add aud, switch to a provider configuration that supports JWT audience validation."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// assert a decoded token carries an aud claim before it reaches validation\nfunc hasAudienceClaim(token string) bool {\n    parts := strings.Split(token, \".\")\n    if len(parts) != 3 {\n        return false\n    }\n    payload, err := base64.RawURLEncoding.DecodeString(parts[1])\n    if err != nil {\n        return false\n    }\n    var claims map[string]json.RawMessage\n    return json.Unmarshal(payload, &claims) == nil && claims[\"aud\"] != nil\n}","typeGuard":null,"tryCatchPattern":"if err := validateTokenAudience(token, audience); err != nil {\n    if strings.Contains(err.Error(), \"audience is absent\") {\n        // add an audience mapper / API identifier in the IdP; the flow must\n        // re-issue a token, so re-login after the fix\n    }\n}","preventionTips":["Configure audience mappers (Keycloak) or API identifiers (Auth0/Azure AD) at app registration time.","Pass the audience parameter in the authorization request - the flow already does; make sure the IdP honors it.","Verify a sample token includes aud before pointing production clients at it."],"tags":["oauth2","jwt","audience","idp","claims"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}