{"record":{"id":"ed9c9e96796d4e6b","repo":"juanfont/headscale","slug":"oidc-issuer-must-be-a-valid-http-s-url","errorCode":null,"errorMessage":"oidc.issuer must be a valid http(s) URL","messagePattern":"oidc\\.issuer must be a valid http\\(s\\) URL","errorType":"validation","errorClass":"errOIDCIssuerInvalid","httpStatus":null,"severity":"error","filePath":"hscontrol/types/config.go","lineNumber":36,"sourceCode":"\t\"github.com/rs/zerolog/log\"\n\t\"github.com/spf13/viper\"\n\t\"go4.org/netipx\"\n\t\"tailscale.com/net/tsaddr\"\n\t\"tailscale.com/tailcfg\"\n\t\"tailscale.com/types/dnstype\"\n\t\"tailscale.com/util/set\"\n)\n\nconst (\n\tPKCEMethodPlain string = \"plain\"\n\tPKCEMethodS256  string = \"S256\"\n\n\tdefaultNodeStoreBatchSize = 100\n)\n\nvar (\n\terrOidcMutuallyExclusive     = errors.New(\"oidc_client_secret and oidc_client_secret_path are mutually exclusive\")\n\terrOIDCIssuerInvalid         = errors.New(\"oidc.issuer must be a valid http(s) URL\")\n\terrOIDCClientIDRequired      = errors.New(\"oidc.client_id is required when oidc.issuer is set\")\n\terrOIDCClientSecretRequired  = errors.New(\"oidc.client_secret or oidc.client_secret_path is required when oidc.issuer is set\")\n\terrServerURLSuffix           = errors.New(\"server_url cannot be part of base_domain in a way that could make the DERP and headscale server unreachable\")\n\terrServerURLSame             = errors.New(\"server_url cannot use the same domain as base_domain in a way that could make the DERP and headscale server unreachable\")\n\terrInvalidPKCEMethod         = errors.New(\"pkce.method must be either 'plain' or 'S256'\")\n\terrTrustedProxyZeroRange     = errors.New(\"0.0.0.0/0 and ::/0 are not allowed\")\n\tErrNoPrefixConfigured        = errors.New(\"no IPv4 or IPv6 prefix configured, minimum one prefix is required\")\n\tErrInvalidAllocationStrategy = errors.New(\"invalid prefix allocation strategy\")\n)\n\ntype IPAllocationStrategy string\n\nconst (\n\tIPAllocationStrategySequential IPAllocationStrategy = \"sequential\"\n\tIPAllocationStrategyRandom     IPAllocationStrategy = \"random\"\n)\n\ntype PolicyMode string","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/types/config.go#L18-L54","documentation":"errOIDCIssuerInvalid is an unexported config validation error in hscontrol/types/config.go:36 returned at config.go:384 (wrapped with the offending value) when oidc.issuer is set but does not parse as a valid http(s) URL. The issuer URL is the base for OIDC discovery, so it must be absolute http or https.","triggerScenarios":"Setting oidc.issuer to a bare hostname ('idp.example.com'), an ldaps:// or other scheme, a URL with spaces, or a value that fails url.Parse/httpscheme checks; copy-pasting the issuer with quotes or trailing characters.","commonSituations":"Forgetting the https:// scheme in the issuer; using the token endpoint URL instead of the issuer base URL; config templating injecting unescaped values.","solutions":["Set oidc.issuer to the full issuer base URL, e.g. https://idp.example.com/realms/main","Use the 'issuer' field from your IdP's /.well-known/openid-configuration, not an endpoint URL","Ensure the scheme is http or https and the URL parses cleanly","Restart headscale and confirm OIDC discovery completes"],"exampleFix":"# before\noidc:\n  issuer: idp.example.com/realms/main\n\n# after\noidc:\n  issuer: https://idp.example.com/realms/main","handlingStrategy":"validation","validationCode":"u, err := url.Parse(issuer)\nif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") || u.Host == \"\" {\n    return errors.New(\"issuer must be a valid http(s) URL\")\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Copy the issuer verbatim from the IdP's /.well-known/openid-configuration","Never use an endpoint URL (token/authorize) as the issuer"],"tags":["headscale","config","oidc","url-validation"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}