{
  "description": "MCPExternalAuthConfig is the Schema for the mcpexternalauthconfigs API.\nMCPExternalAuthConfig resources are namespace-scoped and can only be referenced by\nMCPServer resources within the same namespace. Cross-namespace references\nare not supported for security and isolation reasons.",
  "properties": {
    "apiVersion": {
      "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
      "type": [
        "string",
        "null"
      ]
    },
    "kind": {
      "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
      "type": [
        "string",
        "null"
      ]
    },
    "metadata": {
      "type": [
        "object",
        "null"
      ]
    },
    "spec": {
      "additionalProperties": false,
      "description": "MCPExternalAuthConfigSpec defines the desired state of MCPExternalAuthConfig.\nMCPExternalAuthConfig resources are namespace-scoped and can only be referenced by\nMCPServer resources in the same namespace.",
      "properties": {
        "awsSts": {
          "additionalProperties": false,
          "description": "AWSSts configures AWS STS authentication with SigV4 request signing\nOnly used when Type is \"awsSts\"",
          "properties": {
            "fallbackRoleArn": {
              "description": "FallbackRoleArn is the IAM role ARN to assume when no role mappings match\nUsed as the default role when RoleMappings is empty or no mapping matches\nAt least one of FallbackRoleArn or RoleMappings must be configured (enforced by webhook)",
              "pattern": "^arn:(aws|aws-cn|aws-us-gov):iam::\\d{12}:role/[\\w+=,.@\\-_/]+$",
              "type": [
                "string",
                "null"
              ]
            },
            "region": {
              "description": "Region is the AWS region for the STS endpoint and service (e.g., \"us-east-1\", \"eu-west-1\")",
              "minLength": 1,
              "pattern": "^[a-z]{2}(-[a-z]+)+-\\d+$",
              "type": "string"
            },
            "roleClaim": {
              "default": "groups",
              "description": "RoleClaim is the JWT claim to use for role mapping evaluation\nDefaults to \"groups\" to match common OIDC group claims",
              "type": [
                "string",
                "null"
              ]
            },
            "roleMappings": {
              "description": "RoleMappings defines claim-based role selection rules\nAllows mapping JWT claims (e.g., groups, roles) to specific IAM roles\nLower priority values are evaluated first (higher priority)",
              "items": {
                "additionalProperties": false,
                "description": "RoleMapping defines a rule for mapping JWT claims to IAM roles.\nMappings are evaluated in priority order (lower number = higher priority), and the first\nmatching rule determines which IAM role to assume.\nExactly one of Claim or Matcher must be specified.",
                "properties": {
                  "claim": {
                    "description": "Claim is a simple claim value to match against\nThe claim type is specified by AWSStsConfig.RoleClaim\nFor example, if RoleClaim is \"groups\", this would be a group name\nInternally compiled to a CEL expression: \"\u003cclaim_value\u003e\" in claims[\"\u003crole_claim\u003e\"]\nMutually exclusive with Matcher",
                    "minLength": 1,
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "matcher": {
                    "description": "Matcher is a CEL expression for complex matching against JWT claims\nThe expression has access to a \"claims\" variable containing all JWT claims as map[string]any\nExamples:\n  - \"admins\" in claims[\"groups\"]\n  - claims[\"sub\"] == \"user123\" \u0026\u0026 !(\"act\" in claims)\nMutually exclusive with Claim",
                    "minLength": 1,
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "priority": {
                    "description": "Priority determines evaluation order (lower values = higher priority)\nAllows fine-grained control over role selection precedence\nWhen omitted, this mapping has the lowest possible priority and\nconfiguration order acts as tie-breaker via stable sort",
                    "format": "int32",
                    "minimum": 0,
                    "type": [
                      "integer",
                      "null"
                    ]
                  },
                  "roleArn": {
                    "description": "RoleArn is the IAM role ARN to assume when this mapping matches",
                    "pattern": "^arn:(aws|aws-cn|aws-us-gov):iam::\\d{12}:role/[\\w+=,.@\\-_/]+$",
                    "type": "string"
                  }
                },
                "required": [
                  "roleArn"
                ],
                "type": "object"
              },
              "type": [
                "array",
                "null"
              ],
              "x-kubernetes-list-type": "atomic"
            },
            "service": {
              "default": "aws-mcp",
              "description": "Service is the AWS service name for SigV4 signing\nDefaults to \"aws-mcp\" for AWS MCP Server endpoints",
              "type": [
                "string",
                "null"
              ]
            },
            "sessionDuration": {
              "default": 3600,
              "description": "SessionDuration is the duration in seconds for the STS session\nMust be between 900 (15 minutes) and 43200 (12 hours)\nDefaults to 3600 (1 hour) if not specified",
              "format": "int32",
              "maximum": 43200,
              "minimum": 900,
              "type": [
                "integer",
                "null"
              ]
            },
            "sessionNameClaim": {
              "default": "sub",
              "description": "SessionNameClaim is the JWT claim to use for role session name\nDefaults to \"sub\" to use the subject claim",
              "type": [
                "string",
                "null"
              ]
            }
          },
          "required": [
            "region"
          ],
          "type": [
            "object",
            "null"
          ]
        },
        "bearerToken": {
          "additionalProperties": false,
          "description": "BearerToken configures bearer token authentication\nOnly used when Type is \"bearerToken\"",
          "properties": {
            "tokenSecretRef": {
              "additionalProperties": false,
              "description": "TokenSecretRef references a Kubernetes Secret containing the bearer token",
              "properties": {
                "key": {
                  "description": "Key is the key within the secret",
                  "type": "string"
                },
                "name": {
                  "description": "Name is the name of the secret",
                  "type": "string"
                }
              },
              "required": [
                "key",
                "name"
              ],
              "type": "object"
            }
          },
          "required": [
            "tokenSecretRef"
          ],
          "type": [
            "object",
            "null"
          ]
        },
        "embeddedAuthServer": {
          "additionalProperties": false,
          "description": "EmbeddedAuthServer configures an embedded OAuth2/OIDC authorization server\nOnly used when Type is \"embeddedAuthServer\"",
          "properties": {
            "authorizationEndpointBaseUrl": {
              "description": "AuthorizationEndpointBaseURL overrides the base URL used for the authorization_endpoint\nin the OAuth discovery document. When set, the discovery document will advertise\n`{authorizationEndpointBaseUrl}/oauth/authorize` instead of `{issuer}/oauth/authorize`.\nAll other endpoints (token, registration, JWKS) remain derived from the issuer.\nThis is useful when the browser-facing authorization endpoint needs to be on a\ndifferent host than the issuer used for backend-to-backend calls.\nMust be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash.",
              "pattern": "^https?://[^\\s?#]+[^/\\s?#]$",
              "type": [
                "string",
                "null"
              ]
            },
            "hmacSecretRefs": {
              "description": "HMACSecretRefs references Kubernetes Secrets containing symmetric secrets for signing\nauthorization codes and refresh tokens (opaque tokens).\nCurrent secret must be at least 32 bytes and cryptographically random.\nSupports secret rotation via multiple entries (first is current, rest are for verification).\nIf not specified, an ephemeral secret will be auto-generated (development only -\nauth codes and refresh tokens will be invalid after restart).",
              "items": {
                "additionalProperties": false,
                "description": "SecretKeyRef is a reference to a key within a Secret",
                "properties": {
                  "key": {
                    "description": "Key is the key within the secret",
                    "type": "string"
                  },
                  "name": {
                    "description": "Name is the name of the secret",
                    "type": "string"
                  }
                },
                "required": [
                  "key",
                  "name"
                ],
                "type": "object"
              },
              "type": [
                "array",
                "null"
              ],
              "x-kubernetes-list-type": "atomic"
            },
            "issuer": {
              "description": "Issuer is the issuer identifier for this authorization server.\nThis will be included in the \"iss\" claim of issued tokens.\nMust be a valid HTTPS URL (or HTTP for localhost) without query, fragment, or trailing slash (per RFC 8414).",
              "pattern": "^https?://[^\\s?#]+[^/\\s?#]$",
              "type": "string"
            },
            "signingKeySecretRefs": {
              "description": "SigningKeySecretRefs references Kubernetes Secrets containing signing keys for JWT operations.\nSupports key rotation by allowing multiple keys (oldest keys are used for verification only).\nIf not specified, an ephemeral signing key will be auto-generated (development only -\nJWTs will be invalid after restart).",
              "items": {
                "additionalProperties": false,
                "description": "SecretKeyRef is a reference to a key within a Secret",
                "properties": {
                  "key": {
                    "description": "Key is the key within the secret",
                    "type": "string"
                  },
                  "name": {
                    "description": "Name is the name of the secret",
                    "type": "string"
                  }
                },
                "required": [
                  "key",
                  "name"
                ],
                "type": "object"
              },
              "maxItems": 5,
              "type": [
                "array",
                "null"
              ],
              "x-kubernetes-list-type": "atomic"
            },
            "storage": {
              "additionalProperties": false,
              "description": "Storage configures the storage backend for the embedded auth server.\nIf not specified, defaults to in-memory storage.",
              "properties": {
                "redis": {
                  "additionalProperties": false,
                  "description": "Redis configures the Redis storage backend.\nRequired when type is \"redis\".",
                  "properties": {
                    "aclUserConfig": {
                      "additionalProperties": false,
                      "description": "ACLUserConfig configures Redis ACL user authentication.",
                      "properties": {
                        "passwordSecretRef": {
                          "additionalProperties": false,
                          "description": "PasswordSecretRef references a Secret containing the Redis ACL password.",
                          "properties": {
                            "key": {
                              "description": "Key is the key within the secret",
                              "type": "string"
                            },
                            "name": {
                              "description": "Name is the name of the secret",
                              "type": "string"
                            }
                          },
                          "required": [
                            "key",
                            "name"
                          ],
                          "type": "object"
                        },
                        "usernameSecretRef": {
                          "additionalProperties": false,
                          "description": "UsernameSecretRef references a Secret containing the Redis ACL username.",
                          "properties": {
                            "key": {
                              "description": "Key is the key within the secret",
                              "type": "string"
                            },
                            "name": {
                              "description": "Name is the name of the secret",
                              "type": "string"
                            }
                          },
                          "required": [
                            "key",
                            "name"
                          ],
                          "type": "object"
                        }
                      },
                      "required": [
                        "passwordSecretRef",
                        "usernameSecretRef"
                      ],
                      "type": "object"
                    },
                    "dialTimeout": {
                      "default": "5s",
                      "description": "DialTimeout is the timeout for establishing connections.\nFormat: Go duration string (e.g., \"5s\", \"1m\").",
                      "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "readTimeout": {
                      "default": "3s",
                      "description": "ReadTimeout is the timeout for socket reads.\nFormat: Go duration string (e.g., \"3s\", \"1m\").",
                      "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "sentinelConfig": {
                      "additionalProperties": false,
                      "description": "SentinelConfig holds Redis Sentinel configuration.",
                      "properties": {
                        "db": {
                          "default": 0,
                          "description": "DB is the Redis database number.",
                          "format": "int32",
                          "type": [
                            "integer",
                            "null"
                          ]
                        },
                        "masterName": {
                          "description": "MasterName is the name of the Redis master monitored by Sentinel.",
                          "type": "string"
                        },
                        "sentinelAddrs": {
                          "description": "SentinelAddrs is a list of Sentinel host:port addresses.\nMutually exclusive with SentinelService.",
                          "items": {
                            "type": "string"
                          },
                          "type": [
                            "array",
                            "null"
                          ],
                          "x-kubernetes-list-type": "atomic"
                        },
                        "sentinelService": {
                          "additionalProperties": false,
                          "description": "SentinelService enables automatic discovery from a Kubernetes Service.\nMutually exclusive with SentinelAddrs.",
                          "properties": {
                            "name": {
                              "description": "Name of the Sentinel Service.",
                              "type": "string"
                            },
                            "namespace": {
                              "description": "Namespace of the Sentinel Service (defaults to same namespace).",
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "port": {
                              "default": 26379,
                              "description": "Port of the Sentinel service.",
                              "format": "int32",
                              "type": [
                                "integer",
                                "null"
                              ]
                            }
                          },
                          "required": [
                            "name"
                          ],
                          "type": [
                            "object",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "masterName"
                      ],
                      "type": "object"
                    },
                    "sentinelTls": {
                      "additionalProperties": false,
                      "description": "SentinelTLS configures TLS for connections to Sentinel instances.\nPresence of this field enables TLS. Omit to use plaintext.\nWhen omitted, sentinel connections use plaintext (no fallback to TLS config).",
                      "properties": {
                        "caCertSecretRef": {
                          "additionalProperties": false,
                          "description": "CACertSecretRef references a Secret containing a PEM-encoded CA certificate\nfor verifying the server. When not specified, system root CAs are used.",
                          "properties": {
                            "key": {
                              "description": "Key is the key within the secret",
                              "type": "string"
                            },
                            "name": {
                              "description": "Name is the name of the secret",
                              "type": "string"
                            }
                          },
                          "required": [
                            "key",
                            "name"
                          ],
                          "type": [
                            "object",
                            "null"
                          ]
                        },
                        "insecureSkipVerify": {
                          "description": "InsecureSkipVerify skips TLS certificate verification.\nUse when connecting to services with self-signed certificates.",
                          "type": [
                            "boolean",
                            "null"
                          ]
                        }
                      },
                      "type": [
                        "object",
                        "null"
                      ]
                    },
                    "tls": {
                      "additionalProperties": false,
                      "description": "TLS configures TLS for connections to the Redis/Valkey master.\nPresence of this field enables TLS. Omit to use plaintext.",
                      "properties": {
                        "caCertSecretRef": {
                          "additionalProperties": false,
                          "description": "CACertSecretRef references a Secret containing a PEM-encoded CA certificate\nfor verifying the server. When not specified, system root CAs are used.",
                          "properties": {
                            "key": {
                              "description": "Key is the key within the secret",
                              "type": "string"
                            },
                            "name": {
                              "description": "Name is the name of the secret",
                              "type": "string"
                            }
                          },
                          "required": [
                            "key",
                            "name"
                          ],
                          "type": [
                            "object",
                            "null"
                          ]
                        },
                        "insecureSkipVerify": {
                          "description": "InsecureSkipVerify skips TLS certificate verification.\nUse when connecting to services with self-signed certificates.",
                          "type": [
                            "boolean",
                            "null"
                          ]
                        }
                      },
                      "type": [
                        "object",
                        "null"
                      ]
                    },
                    "writeTimeout": {
                      "default": "3s",
                      "description": "WriteTimeout is the timeout for socket writes.\nFormat: Go duration string (e.g., \"3s\", \"1m\").",
                      "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "aclUserConfig",
                    "sentinelConfig"
                  ],
                  "type": [
                    "object",
                    "null"
                  ]
                },
                "type": {
                  "default": "memory",
                  "description": "Type specifies the storage backend type.\nValid values: \"memory\" (default), \"redis\".",
                  "enum": [
                    "memory",
                    "redis"
                  ],
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "type": [
                "object",
                "null"
              ]
            },
            "tokenLifespans": {
              "additionalProperties": false,
              "description": "TokenLifespans configures the duration that various tokens are valid.\nIf not specified, defaults are applied (access: 1h, refresh: 7d, authCode: 10m).",
              "properties": {
                "accessTokenLifespan": {
                  "description": "AccessTokenLifespan is the duration that access tokens are valid.\nFormat: Go duration string (e.g., \"1h\", \"30m\", \"24h\").\nIf empty, defaults to 1 hour.",
                  "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "authCodeLifespan": {
                  "description": "AuthCodeLifespan is the duration that authorization codes are valid.\nFormat: Go duration string (e.g., \"10m\", \"5m\").\nIf empty, defaults to 10 minutes.",
                  "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "refreshTokenLifespan": {
                  "description": "RefreshTokenLifespan is the duration that refresh tokens are valid.\nFormat: Go duration string (e.g., \"168h\", \"7d\" as \"168h\").\nIf empty, defaults to 7 days (168h).",
                  "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "type": [
                "object",
                "null"
              ]
            },
            "upstreamProviders": {
              "description": "UpstreamProviders configures connections to upstream Identity Providers.\nThe embedded auth server delegates authentication to these providers.\nMCPServer and MCPRemoteProxy support a single upstream; VirtualMCPServer supports multiple.",
              "items": {
                "additionalProperties": false,
                "description": "UpstreamProviderConfig defines configuration for an upstream Identity Provider.",
                "properties": {
                  "name": {
                    "description": "Name uniquely identifies this upstream provider.\nUsed for routing decisions and session binding in multi-upstream scenarios.\nMust be lowercase alphanumeric with hyphens (DNS-label-like).",
                    "maxLength": 63,
                    "minLength": 1,
                    "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$",
                    "type": "string"
                  },
                  "oauth2Config": {
                    "additionalProperties": false,
                    "description": "OAuth2Config contains OAuth 2.0-specific configuration.\nRequired when Type is \"oauth2\", must be nil when Type is \"oidc\".",
                    "properties": {
                      "authorizationEndpoint": {
                        "description": "AuthorizationEndpoint is the URL for the OAuth authorization endpoint.",
                        "pattern": "^https?://.*$",
                        "type": "string"
                      },
                      "clientId": {
                        "description": "ClientID is the OAuth 2.0 client identifier registered with the upstream IDP.",
                        "type": "string"
                      },
                      "clientSecretRef": {
                        "additionalProperties": false,
                        "description": "ClientSecretRef references a Kubernetes Secret containing the OAuth 2.0 client secret.\nOptional for public clients using PKCE instead of client secret.",
                        "properties": {
                          "key": {
                            "description": "Key is the key within the secret",
                            "type": "string"
                          },
                          "name": {
                            "description": "Name is the name of the secret",
                            "type": "string"
                          }
                        },
                        "required": [
                          "key",
                          "name"
                        ],
                        "type": [
                          "object",
                          "null"
                        ]
                      },
                      "redirectUri": {
                        "description": "RedirectURI is the callback URL where the upstream IDP will redirect after authentication.\nWhen not specified, defaults to `{resourceUrl}/oauth/callback` where `resourceUrl` is the\nURL associated with the resource (e.g., MCPServer or vMCP) using this config.",
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "scopes": {
                        "description": "Scopes are the OAuth scopes to request from the upstream IDP.",
                        "items": {
                          "type": "string"
                        },
                        "type": [
                          "array",
                          "null"
                        ],
                        "x-kubernetes-list-type": "atomic"
                      },
                      "tokenEndpoint": {
                        "description": "TokenEndpoint is the URL for the OAuth token endpoint.",
                        "pattern": "^https?://.*$",
                        "type": "string"
                      },
                      "tokenResponseMapping": {
                        "additionalProperties": false,
                        "description": "TokenResponseMapping configures custom field extraction from non-standard token responses.\nSome OAuth providers (e.g., GovSlack) nest token fields under non-standard paths\ninstead of returning them at the top level. When set, ToolHive performs the token\nexchange HTTP call directly and extracts fields using the configured dot-notation paths.\nIf nil, standard OAuth 2.0 token response parsing is used.",
                        "properties": {
                          "accessTokenPath": {
                            "description": "AccessTokenPath is the dot-notation path to the access token in the response.\nExample: \"authed_user.access_token\"",
                            "minLength": 1,
                            "type": "string"
                          },
                          "expiresInPath": {
                            "description": "ExpiresInPath is the dot-notation path to the expires_in value (in seconds).\nIf not specified, defaults to \"expires_in\".",
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "refreshTokenPath": {
                            "description": "RefreshTokenPath is the dot-notation path to the refresh token in the response.\nIf not specified, defaults to \"refresh_token\".",
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "scopePath": {
                            "description": "ScopePath is the dot-notation path to the scope string in the response.\nIf not specified, defaults to \"scope\".",
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "accessTokenPath"
                        ],
                        "type": [
                          "object",
                          "null"
                        ]
                      },
                      "userInfo": {
                        "additionalProperties": false,
                        "description": "UserInfo contains configuration for fetching user information from the upstream provider.\nRequired for OAuth2 providers to resolve user identity.",
                        "properties": {
                          "additionalHeaders": {
                            "additionalProperties": {
                              "type": "string"
                            },
                            "description": "AdditionalHeaders contains extra headers to include in the userinfo request.\nUseful for providers that require specific headers (e.g., GitHub's Accept header).",
                            "type": [
                              "object",
                              "null"
                            ]
                          },
                          "endpointUrl": {
                            "description": "EndpointURL is the URL of the userinfo endpoint.",
                            "pattern": "^https?://.*$",
                            "type": "string"
                          },
                          "fieldMapping": {
                            "additionalProperties": false,
                            "description": "FieldMapping contains custom field mapping configuration for non-standard providers.\nIf nil, standard OIDC field names are used (\"sub\", \"name\", \"email\").",
                            "properties": {
                              "emailFields": {
                                "description": "EmailFields is an ordered list of field names to try for the email address.\nThe first non-empty value found will be used.\nDefault: [\"email\"]",
                                "items": {
                                  "type": "string"
                                },
                                "type": [
                                  "array",
                                  "null"
                                ],
                                "x-kubernetes-list-type": "atomic"
                              },
                              "nameFields": {
                                "description": "NameFields is an ordered list of field names to try for the display name.\nThe first non-empty value found will be used.\nDefault: [\"name\"]",
                                "items": {
                                  "type": "string"
                                },
                                "type": [
                                  "array",
                                  "null"
                                ],
                                "x-kubernetes-list-type": "atomic"
                              },
                              "subjectFields": {
                                "description": "SubjectFields is an ordered list of field names to try for the user ID.\nThe first non-empty value found will be used.\nDefault: [\"sub\"]",
                                "items": {
                                  "type": "string"
                                },
                                "type": [
                                  "array",
                                  "null"
                                ],
                                "x-kubernetes-list-type": "atomic"
                              }
                            },
                            "type": [
                              "object",
                              "null"
                            ]
                          },
                          "httpMethod": {
                            "description": "HTTPMethod is the HTTP method to use for the userinfo request.\nIf not specified, defaults to GET.",
                            "enum": [
                              "GET",
                              "POST"
                            ],
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "endpointUrl"
                        ],
                        "type": "object"
                      }
                    },
                    "required": [
                      "authorizationEndpoint",
                      "clientId",
                      "tokenEndpoint",
                      "userInfo"
                    ],
                    "type": [
                      "object",
                      "null"
                    ]
                  },
                  "oidcConfig": {
                    "additionalProperties": false,
                    "description": "OIDCConfig contains OIDC-specific configuration.\nRequired when Type is \"oidc\", must be nil when Type is \"oauth2\".",
                    "properties": {
                      "clientId": {
                        "description": "ClientID is the OAuth 2.0 client identifier registered with the upstream IDP.",
                        "type": "string"
                      },
                      "clientSecretRef": {
                        "additionalProperties": false,
                        "description": "ClientSecretRef references a Kubernetes Secret containing the OAuth 2.0 client secret.\nOptional for public clients using PKCE instead of client secret.",
                        "properties": {
                          "key": {
                            "description": "Key is the key within the secret",
                            "type": "string"
                          },
                          "name": {
                            "description": "Name is the name of the secret",
                            "type": "string"
                          }
                        },
                        "required": [
                          "key",
                          "name"
                        ],
                        "type": [
                          "object",
                          "null"
                        ]
                      },
                      "issuerUrl": {
                        "description": "IssuerURL is the OIDC issuer URL for automatic endpoint discovery.\nMust be a valid HTTPS URL.",
                        "pattern": "^https://.*$",
                        "type": "string"
                      },
                      "redirectUri": {
                        "description": "RedirectURI is the callback URL where the upstream IDP will redirect after authentication.\nWhen not specified, defaults to `{resourceUrl}/oauth/callback` where `resourceUrl` is the\nURL associated with the resource (e.g., MCPServer or vMCP) using this config.",
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "scopes": {
                        "description": "Scopes are the OAuth scopes to request from the upstream IDP.\nIf not specified, defaults to [\"openid\", \"offline_access\"].",
                        "items": {
                          "type": "string"
                        },
                        "type": [
                          "array",
                          "null"
                        ],
                        "x-kubernetes-list-type": "atomic"
                      },
                      "userInfoOverride": {
                        "additionalProperties": false,
                        "description": "UserInfoOverride allows customizing UserInfo fetching behavior for OIDC providers.\nBy default, the UserInfo endpoint is discovered automatically via OIDC discovery.\nUse this to override the endpoint URL, HTTP method, or field mappings for providers\nthat return non-standard claim names in their UserInfo response.",
                        "properties": {
                          "additionalHeaders": {
                            "additionalProperties": {
                              "type": "string"
                            },
                            "description": "AdditionalHeaders contains extra headers to include in the userinfo request.\nUseful for providers that require specific headers (e.g., GitHub's Accept header).",
                            "type": [
                              "object",
                              "null"
                            ]
                          },
                          "endpointUrl": {
                            "description": "EndpointURL is the URL of the userinfo endpoint.",
                            "pattern": "^https?://.*$",
                            "type": "string"
                          },
                          "fieldMapping": {
                            "additionalProperties": false,
                            "description": "FieldMapping contains custom field mapping configuration for non-standard providers.\nIf nil, standard OIDC field names are used (\"sub\", \"name\", \"email\").",
                            "properties": {
                              "emailFields": {
                                "description": "EmailFields is an ordered list of field names to try for the email address.\nThe first non-empty value found will be used.\nDefault: [\"email\"]",
                                "items": {
                                  "type": "string"
                                },
                                "type": [
                                  "array",
                                  "null"
                                ],
                                "x-kubernetes-list-type": "atomic"
                              },
                              "nameFields": {
                                "description": "NameFields is an ordered list of field names to try for the display name.\nThe first non-empty value found will be used.\nDefault: [\"name\"]",
                                "items": {
                                  "type": "string"
                                },
                                "type": [
                                  "array",
                                  "null"
                                ],
                                "x-kubernetes-list-type": "atomic"
                              },
                              "subjectFields": {
                                "description": "SubjectFields is an ordered list of field names to try for the user ID.\nThe first non-empty value found will be used.\nDefault: [\"sub\"]",
                                "items": {
                                  "type": "string"
                                },
                                "type": [
                                  "array",
                                  "null"
                                ],
                                "x-kubernetes-list-type": "atomic"
                              }
                            },
                            "type": [
                              "object",
                              "null"
                            ]
                          },
                          "httpMethod": {
                            "description": "HTTPMethod is the HTTP method to use for the userinfo request.\nIf not specified, defaults to GET.",
                            "enum": [
                              "GET",
                              "POST"
                            ],
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "endpointUrl"
                        ],
                        "type": [
                          "object",
                          "null"
                        ]
                      }
                    },
                    "required": [
                      "clientId",
                      "issuerUrl"
                    ],
                    "type": [
                      "object",
                      "null"
                    ]
                  },
                  "type": {
                    "description": "Type specifies the provider type: \"oidc\" or \"oauth2\"",
                    "enum": [
                      "oidc",
                      "oauth2"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "name",
                  "type"
                ],
                "type": "object"
              },
              "minItems": 1,
              "type": "array",
              "x-kubernetes-list-map-keys": [
                "name"
              ],
              "x-kubernetes-list-type": "map"
            }
          },
          "required": [
            "issuer",
            "upstreamProviders"
          ],
          "type": [
            "object",
            "null"
          ]
        },
        "headerInjection": {
          "additionalProperties": false,
          "description": "HeaderInjection configures custom HTTP header injection\nOnly used when Type is \"headerInjection\"",
          "properties": {
            "headerName": {
              "description": "HeaderName is the name of the HTTP header to inject",
              "minLength": 1,
              "type": "string"
            },
            "valueSecretRef": {
              "additionalProperties": false,
              "description": "ValueSecretRef references a Kubernetes Secret containing the header value",
              "properties": {
                "key": {
                  "description": "Key is the key within the secret",
                  "type": "string"
                },
                "name": {
                  "description": "Name is the name of the secret",
                  "type": "string"
                }
              },
              "required": [
                "key",
                "name"
              ],
              "type": "object"
            }
          },
          "required": [
            "headerName",
            "valueSecretRef"
          ],
          "type": [
            "object",
            "null"
          ]
        },
        "tokenExchange": {
          "additionalProperties": false,
          "description": "TokenExchange configures RFC-8693 OAuth 2.0 Token Exchange\nOnly used when Type is \"tokenExchange\"",
          "properties": {
            "audience": {
              "description": "Audience is the target audience for the exchanged token",
              "type": "string"
            },
            "clientId": {
              "description": "ClientID is the OAuth 2.0 client identifier\nOptional for some token exchange flows (e.g., Google Cloud Workforce Identity)",
              "type": [
                "string",
                "null"
              ]
            },
            "clientSecretRef": {
              "additionalProperties": false,
              "description": "ClientSecretRef is a reference to a secret containing the OAuth 2.0 client secret\nOptional for some token exchange flows (e.g., Google Cloud Workforce Identity)",
              "properties": {
                "key": {
                  "description": "Key is the key within the secret",
                  "type": "string"
                },
                "name": {
                  "description": "Name is the name of the secret",
                  "type": "string"
                }
              },
              "required": [
                "key",
                "name"
              ],
              "type": [
                "object",
                "null"
              ]
            },
            "externalTokenHeaderName": {
              "description": "ExternalTokenHeaderName is the name of the custom header to use for the exchanged token.\nIf set, the exchanged token will be added to this custom header (e.g., \"X-Upstream-Token\").\nIf empty or not set, the exchanged token will replace the Authorization header (default behavior).",
              "type": [
                "string",
                "null"
              ]
            },
            "scopes": {
              "description": "Scopes is a list of OAuth 2.0 scopes to request for the exchanged token",
              "items": {
                "type": "string"
              },
              "type": [
                "array",
                "null"
              ],
              "x-kubernetes-list-type": "atomic"
            },
            "subjectProviderName": {
              "description": "SubjectProviderName is the name of the upstream provider whose token is used as the\nRFC 8693 subject token instead of identity.Token when performing token exchange.\nWhen left empty and an embedded authorization server is configured on the VirtualMCPServer,\nthe controller automatically populates this field with the first configured upstream\nprovider name. Set it explicitly to override that default or to select a specific\nprovider when multiple upstreams are configured.",
              "type": [
                "string",
                "null"
              ]
            },
            "subjectTokenType": {
              "description": "SubjectTokenType is the type of the incoming subject token.\nAccepts short forms: \"access_token\" (default), \"id_token\", \"jwt\"\nOr full URNs: \"urn:ietf:params:oauth:token-type:access_token\",\n              \"urn:ietf:params:oauth:token-type:id_token\",\n              \"urn:ietf:params:oauth:token-type:jwt\"\nFor Google Workload Identity Federation with OIDC providers (like Okta), use \"id_token\"",
              "pattern": "^(access_token|id_token|jwt|urn:ietf:params:oauth:token-type:(access_token|id_token|jwt))?$",
              "type": [
                "string",
                "null"
              ]
            },
            "tokenUrl": {
              "description": "TokenURL is the OAuth 2.0 token endpoint URL for token exchange",
              "type": "string"
            }
          },
          "required": [
            "audience",
            "tokenUrl"
          ],
          "type": [
            "object",
            "null"
          ]
        },
        "type": {
          "description": "Type is the type of external authentication to configure",
          "enum": [
            "tokenExchange",
            "headerInjection",
            "bearerToken",
            "unauthenticated",
            "embeddedAuthServer",
            "awsSts",
            "upstreamInject"
          ],
          "type": "string"
        },
        "upstreamInject": {
          "additionalProperties": false,
          "description": "UpstreamInject configures upstream token injection for backend requests.\nOnly used when Type is \"upstreamInject\".",
          "properties": {
            "providerName": {
              "description": "ProviderName is the name of the upstream IDP provider whose access token\nshould be injected as the Authorization: Bearer header.",
              "minLength": 1,
              "type": "string"
            }
          },
          "required": [
            "providerName"
          ],
          "type": [
            "object",
            "null"
          ]
        }
      },
      "required": [
        "type"
      ],
      "type": [
        "object",
        "null"
      ],
      "x-kubernetes-validations": [
        {
          "message": "tokenExchange configuration must be set if and only if type is 'tokenExchange'",
          "rule": "self.type == 'tokenExchange' ? has(self.tokenExchange) : !has(self.tokenExchange)"
        },
        {
          "message": "headerInjection configuration must be set if and only if type is 'headerInjection'",
          "rule": "self.type == 'headerInjection' ? has(self.headerInjection) : !has(self.headerInjection)"
        },
        {
          "message": "bearerToken configuration must be set if and only if type is 'bearerToken'",
          "rule": "self.type == 'bearerToken' ? has(self.bearerToken) : !has(self.bearerToken)"
        },
        {
          "message": "embeddedAuthServer configuration must be set if and only if type is 'embeddedAuthServer'",
          "rule": "self.type == 'embeddedAuthServer' ? has(self.embeddedAuthServer) : !has(self.embeddedAuthServer)"
        },
        {
          "message": "awsSts configuration must be set if and only if type is 'awsSts'",
          "rule": "self.type == 'awsSts' ? has(self.awsSts) : !has(self.awsSts)"
        },
        {
          "message": "upstreamInject configuration must be set if and only if type is 'upstreamInject'",
          "rule": "self.type == 'upstreamInject' ? has(self.upstreamInject) : !has(self.upstreamInject)"
        },
        {
          "message": "no configuration must be set when type is 'unauthenticated'",
          "rule": "self.type == 'unauthenticated' ? (!has(self.tokenExchange) \u0026\u0026 !has(self.headerInjection) \u0026\u0026 !has(self.bearerToken) \u0026\u0026 !has(self.embeddedAuthServer) \u0026\u0026 !has(self.awsSts) \u0026\u0026 !has(self.upstreamInject)) : true"
        }
      ]
    },
    "status": {
      "additionalProperties": false,
      "description": "MCPExternalAuthConfigStatus defines the observed state of MCPExternalAuthConfig",
      "properties": {
        "conditions": {
          "description": "Conditions represent the latest available observations of the MCPExternalAuthConfig's state",
          "items": {
            "additionalProperties": false,
            "description": "Condition contains details for one aspect of the current state of this API Resource.",
            "properties": {
              "lastTransitionTime": {
                "description": "lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.",
                "format": "date-time",
                "type": "string"
              },
              "message": {
                "description": "message is a human readable message indicating details about the transition.\nThis may be an empty string.",
                "maxLength": 32768,
                "type": "string"
              },
              "observedGeneration": {
                "description": "observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.",
                "format": "int64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "reason": {
                "description": "reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.",
                "maxLength": 1024,
                "minLength": 1,
                "pattern": "^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$",
                "type": "string"
              },
              "status": {
                "description": "status of the condition, one of True, False, Unknown.",
                "enum": [
                  "True",
                  "False",
                  "Unknown"
                ],
                "type": "string"
              },
              "type": {
                "description": "type of condition in CamelCase or in foo.example.com/CamelCase.",
                "maxLength": 316,
                "pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$",
                "type": "string"
              }
            },
            "required": [
              "lastTransitionTime",
              "message",
              "reason",
              "status",
              "type"
            ],
            "type": "object"
          },
          "type": [
            "array",
            "null"
          ],
          "x-kubernetes-list-map-keys": [
            "type"
          ],
          "x-kubernetes-list-type": "map"
        },
        "configHash": {
          "description": "ConfigHash is a hash of the current configuration for change detection",
          "type": [
            "string",
            "null"
          ]
        },
        "observedGeneration": {
          "description": "ObservedGeneration is the most recent generation observed for this MCPExternalAuthConfig.\nIt corresponds to the MCPExternalAuthConfig's generation, which is updated on mutation by the API Server.",
          "format": "int64",
          "type": [
            "integer",
            "null"
          ]
        },
        "referencingWorkloads": {
          "description": "ReferencingWorkloads is a list of workload resources that reference this MCPExternalAuthConfig.\nEach entry identifies the workload by kind and name.",
          "items": {
            "additionalProperties": false,
            "description": "WorkloadReference identifies a workload that references a shared configuration resource.\nNamespace is implicit — cross-namespace references are not supported.",
            "properties": {
              "kind": {
                "description": "Kind is the type of workload resource",
                "enum": [
                  "MCPServer",
                  "VirtualMCPServer",
                  "MCPRemoteProxy"
                ],
                "type": "string"
              },
              "name": {
                "description": "Name is the name of the workload resource",
                "minLength": 1,
                "type": "string"
              }
            },
            "required": [
              "kind",
              "name"
            ],
            "type": "object"
          },
          "type": [
            "array",
            "null"
          ],
          "x-kubernetes-list-map-keys": [
            "name"
          ],
          "x-kubernetes-list-type": "map"
        }
      },
      "type": [
        "object",
        "null"
      ]
    }
  },
  "type": "object"
}