{"record":{"id":"7b07947bc17b1f65","repo":"EpicGames/lore","slug":"environment-endpoint-auth-url-and-server-auth-resource-claim","errorCode":null,"errorMessage":"[environment.endpoint] auth_url and [server.auth] resource_claim are both set: with auth_url configured, every check calls the auth service and resource_claim does nothing. Remove auth_url to authorize from the token's resource claim, or remove resource_claim to stay on the gRPC auth service.","messagePattern":"\\[environment\\.endpoint\\] auth_url and \\[server\\.auth\\] resource_claim are both set: with auth_url configured, every check calls the auth service and resource_claim does nothing\\. Remove auth_url to authorize from the token's resource claim, or remove resource_claim to stay on the gRPC auth service\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"lore-server/src/authnz/repository_authorizer.rs","lineNumber":218,"sourceCode":"/// - `auth_url` set → the gRPC online auth check\n/// - `resource_claim` set → `ResourceGrants`\n/// - otherwise → `GlobalGrants`\npub fn select_repository_authorizer(\n    auth: Option<&AuthSettings>,\n    auth_url: Option<&str>,\n) -> anyhow::Result<AuthorizerSelection> {\n    let Some(auth) = auth else {\n        return match auth_url {\n            None => Ok(AuthorizerSelection::AllowAll),\n            Some(_) => bail!(\n                \"[environment.endpoint] auth_url is set but [server.auth] is not: without \\\n                 [server.auth] tokens are not verified. Add [server.auth] (jwt_issuer, jwt_audience) \\\n                 to enable verification, or remove auth_url.\"\n            ),\n        };\n    };\n    match (auth_url, auth.resource_claim.as_deref()) {\n        (Some(_), Some(_)) => bail!(\n            \"[environment.endpoint] auth_url and [server.auth] resource_claim are both set: \\\n             with auth_url configured, every check calls the auth service and resource_claim \\\n             does nothing. Remove auth_url to authorize from the token's resource claim, or \\\n             remove resource_claim to stay on the gRPC auth service.\"\n        ),\n        (Some(_), None) => Ok(AuthorizerSelection::AuthClient),\n        (None, Some(_)) => Ok(AuthorizerSelection::ResourceGrants),\n        (None, None) => Ok(AuthorizerSelection::GlobalGrants),\n    }\n}\n\n/// Creates the authorizer [`select_repository_authorizer`] picks for this\n/// configuration. Built once at startup and shared by every server.\npub fn repository_authorizer(\n    auth: Option<&AuthSettings>,\n    auth_url: Option<String>,\n) -> anyhow::Result<Arc<dyn RepositoryAuthorizer>> {\n    let selection = select_repository_authorizer(auth, auth_url.as_deref())?;","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/EpicGames/lore/blob/074eb0b0d1194c997d7cf28b55519e3e197b3e23/lore-server/src/authnz/repository_authorizer.rs#L200-L236","documentation":"select_repository_authorizer rejects a config where both auth_url and [server.auth] resource_claim are set: with auth_url configured every authorization check calls the external auth service, so resource_claim would silently do nothing. This is treated as a mutually-exclusive configuration conflict and startup fails.","triggerScenarios":"Configuring environment.endpoint.auth_url AND server.auth.resource_claim simultaneously; select_repository_authorizer matches (Some(_), Some(_)) and bails during repository_authorizer startup or validate_auth_config.","commonSituations":"Operators enabling local resource-claim authorization but forgetting to remove the previously set auth_url; merging config files where both auth modes accumulated; toggling between gRPC auth-service mode and claim-based mode during migration.","solutions":["Remove auth_url from [environment.endpoint] to authorize from the token's resource_claim.","Or remove resource_claim from [server.auth] to keep using the gRPC auth service.","Re-run startup after the change; validate_auth_config should now select AllowAll/AuthClient/claim-based authorizer cleanly."],"exampleFix":"// before (config)\n[server.auth]\njwt_issuer = \"https://auth.example.com\"\njwt_audience = \"aud\"\nresource_claim = \"permissions\"\n[environment.endpoint]\nauth_url = \"https://auth.example.com\"\n// after (claim-based auth)\n[server.auth]\njwt_issuer = \"https://auth.example.com\"\njwt_audience = \"aud\"\nresource_claim = \"permissions\"","handlingStrategy":"validation","validationCode":"// config-load validation\nif config.environment.endpoint.auth_url.is_some()\n    && config.server.auth.as_ref().and_then(|a| a.resource_claim.as_deref()).is_some() {\n    return Err(anyhow!(\"auth_url and server.auth.resource_claim are mutually exclusive\"));\n}","typeGuard":null,"tryCatchPattern":"match select_repository_authorizer(&auth_opt, &auth_url_opt) {\n    Ok(sel) => start_server(sel),\n    Err(e) => { eprintln!(\"conflicting auth config: {e:#}\"); std::process::exit(2); }\n}","preventionTips":["Pick one authorization mode per deployment: auth service OR resource claim.","Add a config lint/test asserting the two settings never coexist.","During migrations, remove auth_url in the same change that adds resource_claim.","Run validate_auth_config before deploying config changes."],"tags":["rust","auth","configuration","startup","conflict"],"backgroundTag":"conflicting-config-options","analyzedSha":"074eb0b0d1194c997d7cf28b55519e3e197b3e23","analyzedAt":"2026-09-13T09:00:57.509Z","contentChangedAt":"2026-09-13T09:00:57.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}