{"record":{"id":"4c63893ffc8e75ba","repo":"medusajs/medusa","slug":"oidc-engine-requires-an-issuer-option","errorCode":null,"errorMessage":"OIDC engine requires an 'issuer' option","messagePattern":"OIDC engine requires an 'issuer' option","errorType":"validation","errorClass":"MedusaError","httpStatus":400,"severity":"critical","filePath":"packages/modules/providers/auth-oidc/src/engine/engine.ts","lineNumber":65,"sourceCode":"  protected readonly options_: OidcEngineOptions\n  protected readonly discoveryCacheTtlMs_: number\n  protected readonly httpTimeoutMs_: number\n  protected readonly cache_?: ICacheService\n\n  /**\n   * The memoized OIDC client. `openid-client` v5 caches the JWKS keystore per\n   * `Issuer` instance, so building a fresh client on every call would refetch\n   * the JWKS over HTTP on every login callback. The client is built lazily and\n   * reused until the discovery cache entry expires; when all endpoints are\n   * configured explicitly (no discovery), it's cached indefinitely, since the\n   * engine's options are immutable per instance.\n   */\n  protected clientPromise_?: Promise<Client>\n  protected clientExpiresAt_ = 0\n\n  constructor(options: OidcEngineOptions, cache?: ICacheService) {\n    if (!options?.issuer) {\n      throw new MedusaError(\n        MedusaError.Types.INVALID_DATA,\n        \"OIDC engine requires an 'issuer' option\"\n      )\n    }\n    if (!options.client_id) {\n      throw new MedusaError(\n        MedusaError.Types.INVALID_DATA,\n        \"OIDC engine requires a 'client_id' option\"\n      )\n    }\n    if (!options.callback_url) {\n      throw new MedusaError(\n        MedusaError.Types.INVALID_DATA,\n        \"OIDC engine requires a 'callback_url' option\"\n      )\n    }\n\n    assertSecureUrl(options.issuer, \"issuer\")","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/providers/auth-oidc/src/engine/engine.ts#L47-L83","documentation":"The OIDC auth provider's engine (openid-client wrapper) requires an `issuer` option — the URL of the OIDC provider's configuration endpoint. The constructor throws INVALID_DATA when it is missing, failing at startup.","triggerScenarios":"Configuring the auth-oidc provider whose options are forwarded to the engine without an `issuer`, e.g. only passing client_id/secret.","commonSituations":"Missing or misnamed issuer env var, using a discovery URL that isn't the base issuer URL (e.g. including /.well-known/openid-configuration), or the IdP not supporting OIDC discovery.","solutions":["Set issuer to the IdP's base URL, e.g. https://accounts.google.com or https://yourorg.okta.com — the engine appends /.well-known/openid-configuration itself","Verify the URL resolves by opening {issuer}/.well-known/openid-configuration in a browser","Check the env var feeding issuer is set in the runtime environment"],"exampleFix":"// before\n{ id: 'oidc', resolve: '@medusajs/auth-oidc', options: { client_id, client_secret, callback_url } }\n// after\n{ id: 'oidc', resolve: '@medusajs/auth-oidc', options: { issuer: process.env.OIDC_ISSUER, client_id, client_secret, callback_url } }","handlingStrategy":"validation","validationCode":"const issuer = process.env.OIDC_ISSUER\nif (!issuer || !URL.parse(issuer)) throw new Error('OIDC_ISSUER must be the IdP base URL')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Point issuer at the base URL only; the engine fetches /.well-known/openid-configuration","Verify discovery works with a curl before deploying","Add config linting for required OIDC options"],"tags":["oidc","oauth","auth-provider","module-config","startup"],"backgroundTag":"oauth-provider-misconfigured","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}