medusajs/medusa · error · MedusaError
OIDC '${label}' must be a valid URL
Error message
OIDC '${label}' must be a valid URL What it means
assertSecureUrl is used to validate the issuer and callback_url options. If new URL(value) throws (malformed string, empty, missing scheme), it raises INVALID_DATA saying the '<label>' must be a valid URL.
Source
Thrown at packages/modules/providers/auth-oidc/src/utils/assert-secure-url.ts:12
import { isProduction, MedusaError } from "@medusajs/framework/utils"
/**
* Asserts that a URL is `https`. Outside of production, `http` is allowed for
* localhost so local development and testing remain possible.
*/
export const assertSecureUrl = (value: string, label: string): void => {
let url: URL
try {
url = new URL(value)
} catch (e) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`OIDC '${label}' must be a valid URL`
)
}
const isLocalhost =
url.hostname === "localhost" ||
url.hostname === "127.0.0.1" ||
url.hostname === "::1" ||
url.hostname === "[::1]"
const allowsHttp = isLocalhost && !isProduction()
if (url.protocol !== "https:" && !(url.protocol === "http:" && allowsHttp)) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`OIDC '${label}' must use https (http is only allowed for localhost outside of production)`
)View on GitHub (pinned to 5e06e544a2)
Solutions
- Prefix the scheme: issuer must look like https://auth.example.com (issuer is the base URL, no /.well-known/... path needed).
- Trim and sanitize env values; check for stray quotes from .env formatting.
- Log the resolved value at startup to catch undefined interpolation before it reaches the provider.
Example fix
// before
options: { issuer: "auth.example.com", ... }
// after
options: { issuer: "https://auth.example.com", ... } Defensive patterns
Strategy: validation
Validate before calling
function isValidUrl(value: string): boolean {
try { new URL(value); return true } catch { return false }
}
if (!isValidUrl(options.issuer)) throw new Error("issuer must be a valid URL including scheme") Type guard
const isValidHttpUrl = (v: string): v is \`https://\${string}\` => { try { const u = new URL(v); return u.protocol === "https:" || u.protocol === "http:" } catch { return false } } Try / catch
try { assertSecureUrl(value, "issuer") } catch (e) { if (e instanceof MedusaError && /must be a valid URL/.test(e.message)) { /* fix the string (add https://) */ } throw e } Prevention
- Always include the https:// scheme in issuer and callback_url.
- Trim env values and strip stray quotes.
- Log resolved URLs at startup to catch interpolation bugs.
When it happens
Trigger: Passing issuer: "auth.example.com" (no scheme), issuer: "" , or issuer: undefined-as-string; a callback_url with unencoded spaces or a stray trailing character.
Common situations: Missing https:// prefix — the single most common cause; env var containing quotes or whitespace; concatenation bugs producing strings like "https://example.com/none" + undefined; copy-pasting the well-known path into issuer with a typo.
Related errors
- OIDC engine requires a 'callback_url' option
- OIDC provider requires an 'issuer' option
- OIDC provider requires a 'client_id' option
- OIDC provider requires a 'callback_url' option
- OIDC engine requires an 'issuer' option
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/464a78dc1cb622f4.
Report an issue: GitHub.