{"record":{"id":"95b03543a66c1688","repo":"infiniflow/ragflow","slug":"missing-issuer-in-configuration","errorCode":null,"errorMessage":"Missing issuer in configuration.","messagePattern":"Missing issuer in configuration\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"api/apps/auth/oidc.py","lineNumber":77,"sourceCode":"    crucially, the fallback is to RS256, **never** to whatever the JWT\n    header claims at verification time.\n    \"\"\"\n    advertised = metadata.get(\"id_token_signing_alg_values_supported\") or []\n    if not isinstance(advertised, (list, tuple)):\n        advertised = []\n    safe = [a for a in advertised if isinstance(a, str) and a in _ALLOWED_OIDC_SIGNING_ALGS]\n    return safe or list(_DEFAULT_OIDC_SIGNING_ALGS)\n\n\nclass OIDCClient(OAuthClient):\n    def __init__(self, config):\n        \"\"\"\n        Initialize the OIDCClient with the provider's configuration.\n        Use `issuer` as the single source of truth for configuration discovery.\n        \"\"\"\n        self.issuer = config.get(\"issuer\")\n        if not self.issuer:\n            raise ValueError(\"Missing issuer in configuration.\")\n\n        oidc_metadata = self._load_oidc_metadata(self.issuer)\n        config.update(\n            {\n                \"issuer\": oidc_metadata[\"issuer\"],\n                \"jwks_uri\": oidc_metadata[\"jwks_uri\"],\n                \"authorization_url\": oidc_metadata[\"authorization_endpoint\"],\n                \"token_url\": oidc_metadata[\"token_endpoint\"],\n                \"userinfo_url\": oidc_metadata[\"userinfo_endpoint\"],\n            }\n        )\n\n        super().__init__(config)\n        self.issuer = config[\"issuer\"]\n        self.jwks_uri = config[\"jwks_uri\"]\n        # Pin the accepted ID-token signing algorithms at construction time\n        # from a trusted source (provider metadata + safe allowlist) so the\n        # JWT verification step in :meth:`parse_id_token` cannot be tricked","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/api/apps/auth/oidc.py#L59-L95","documentation":"OIDCClient.__init__ treats config['issuer'] as the single source of truth for discovery and raises ValueError('Missing issuer in configuration.') (api/apps/auth/oidc.py:77) when it is absent or falsy. This fires before any network call - the OIDC client cannot be constructed without an issuer URL.","triggerScenarios":"Auth config declares type 'oidc' but omits the issuer key; issuer is set to an empty string or null; the config was written for a plain OAuth2 provider (endpoints listed individually) and the type was later changed to 'oidc' without adding issuer.","commonSituations":"Editing provider settings by hand; type inference surprises - an empty type WITH an issuer silently becomes 'oidc', so a half-finished config reaches OIDCClient; config migrations dropping the field.","solutions":["Add the issuer URL (the base URL of the IdP, no /.well-known suffix), e.g. \"issuer\": \"https://accounts.google.com\".","Or switch type to 'oauth2' and configure authorization/token/userinfo endpoints explicitly if you cannot use discovery.","If you meant GitHub login, use type 'github' instead of 'oidc'.","Double-check trailing content: issuer must be the bare base URL; the code appends /.well-known/openid-configuration itself."],"exampleFix":"// before\n{\"type\": \"oidc\", \"client_id\": \"...\", \"client_secret\": \"...\"}\n\n// after\n{\"type\": \"oidc\", \"issuer\": \"https://sso.example.com/realms/main\", \"client_id\": \"...\", \"client_secret\": \"...\"}","handlingStrategy":"validation","validationCode":"if str(config.get(\"type\", \"\")).lower() in (\"\", \"oidc\"):\n    issuer = config.get(\"issuer\")\n    if not issuer or not str(issuer).startswith((\"http://\", \"https://\")):\n        raise ValueError(\"OIDC providers require a valid issuer URL\")","typeGuard":"def has_oidc_issuer(config: dict) -> bool:\n    issuer = config.get(\"issuer\")\n    return isinstance(issuer, str) and issuer.strip() != \"\"","tryCatchPattern":"try:\n    client = OIDCClient(config)\nexcept ValueError as e:\n    if \"Missing issuer\" in str(e):\n        raise ConfigError(\"Add 'issuer' to the OIDC provider configuration\") from e\n    raise","preventionTips":["Schema-validate auth configs: type=oidc implies required issuer.","Store issuer as the bare IdP base URL; the client appends the well-known path.","Use configuration UI validation or a JSON schema so empty issuers fail at save time."],"tags":["auth","oidc","configuration","validation"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}