
    kKj\_                         d Z ddlmZ ddlmZmZ ddlZddlmZ ddl	m
Z
mZmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ  ee      ZdZ G d de      Z G d de      Zy)a  OIDC Proxy Provider for FastMCP.

This provider acts as a transparent proxy to an upstream OIDC compliant Authorization
Server. It leverages the OAuthProxy class to handle Dynamic Client Registration and
forwarding of all OAuth flows.

This implementation is based on:
    OpenID Connect Discovery 1.0 - https://openid.net/specs/openid-connect-discovery-1_0.html
    OAuth 2.0 Authorization Server Metadata - https://datatracker.ietf.org/doc/html/rfc8414
    )Sequence)AnyLiteralN)AsyncKeyValue)
AnyHttpUrl	BaseModelmodel_validator)Self)TokenVerifier)
OAuthProxy)UpstreamTokenSet)JWTVerifier)
get_logger
   c            	          e Zd ZU dZdZeed<   dZee	z  dz  ed<   dZ
ee	z  dz  ed<   dZee	z  dz  ed<   dZee	z  dz  ed<   dZee	z  dz  ed	<   dZee	z  dz  ed
<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZee	   dz  ed<   dZ ee	   dz  ed<   dZ!ee	   dz  ed<   dZ"ee	   dz  ed<   dZ#ee	   dz  ed<   dZ$ee	z  dz  ed<   dZ%ee	   dz  ed <   dZ&ee	   dz  ed!<   dZ'edz  ed"<   dZ(edz  ed#<   dZ)edz  ed$<   dZ*edz  ed%<   dZ+ee	z  dz  ed&<   dZ,ee	z  dz  ed'<   dZ-ee	z  dz  ed(<   dZ.ee	   dz  ed)<   dZ/ee	   dz  ed*<   dZ0ee	z  dz  ed+<   dZ1ee	   dz  ed,<   dZ2ee	   dz  ed-<   dZ3ee	   dz  ed.<   dZ4e	dz  ed/<    e5d01      d2e6fd3       Z7e8d4ededz  d5e9dz  d2e6fd6       Z:y)7OIDCConfigurationzOIDC Configuration.

    See:
        https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
        https://datatracker.ietf.org/doc/html/rfc8414#section-2
    TstrictNissuerauthorization_endpointtoken_endpointuserinfo_endpointjwks_uriregistration_endpointscopes_supportedresponse_types_supportedresponse_modes_supportedgrant_types_supportedacr_values_supportedsubject_types_supported%id_token_signing_alg_values_supported(id_token_encryption_alg_values_supported(id_token_encryption_enc_values_supported%userinfo_signing_alg_values_supported(userinfo_encryption_alg_values_supported(userinfo_encryption_enc_values_supported+request_object_signing_alg_values_supported.request_object_encryption_alg_values_supported.request_object_encryption_enc_values_supported%token_endpoint_auth_methods_supported0token_endpoint_auth_signing_alg_values_supporteddisplay_values_supportedclaim_types_supportedclaims_supportedservice_documentationclaims_locales_supportedui_locales_supportedclaims_parameter_supportedrequest_parameter_supportedrequest_uri_parameter_supported require_request_uri_registrationop_policy_uri
op_tos_urirevocation_endpoint*revocation_endpoint_auth_methods_supported5revocation_endpoint_auth_signing_alg_values_supportedintrospection_endpoint-introspection_endpoint_auth_methods_supported8introspection_endpoint_auth_signing_alg_values_supported code_challenge_methods_supportedsigned_metadataafter)modereturnc                       j                   s S ddt        dt        ddf fd} |dd        |dd        |d	d        |d
d        |d        |d        |d        S )zEnforce strict rules.attris_urlrA   Nc                    t        | d       }|s%d|  }t        j                  |       t        |      |rt	        |t
              ry 	 t        |       y # t        $ r+}d|  }t        j                  |       t        |      |d }~ww xY w)Nz)Missing required configuration metadata: z(Invalid URL for configuration metadata: )getattrloggererror
ValueError
isinstancer   	Exception)rC   rD   valuemessageeselfs        o/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/fastmcp/server/auth/oidc_proxy.pyenforcez2OIDCConfiguration._enforce_strict.<locals>.enforcez   s    D$-EEdVLW% ))Zz:15! 1DTFKW% )q01s   
A 	B
&BB
r   Tr   r   r   r   r   r    )F)r   strbool)rO   rQ   s   ` rP   _enforce_strictz!OIDCConfiguration._enforce_strictt   sw     {{K	1# 	1t 	1 	1" 	$($/ $'
D!*+)*78    
config_urltimeout_secondsc                   i }|||d<   	 t        j                  t        |      fi |}|j                          |j	                         }|||d<   | j                  |      S # t        $ r t        j                  d|         w xY w)zGet the OIDC configuration for the specified config URL.

        Args:
            config_url: The OIDC config URL
            strict: The strict flag for the configuration
            timeout_seconds: HTTP request timeout in seconds
        timeoutr   z1Unable to get OIDC configuration for config url: )	httpxgetrR   raise_for_statusjsonmodel_validaterK   rG   	exception)clsrV   r   rW   
get_kwargsresponseconfig_datas          rP   get_oidc_configurationz(OIDCConfiguration.get_oidc_configuration   s     &(
&$3Jy!	yyZ?J?H%%'"--/K!(.H%%%k22 	CJ<P 		s   AA" "#B);__name__
__module____qualname____doc__r   rS   __annotations__r   r   rR   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r	   r
   rT   classmethodintrd    rU   rP   r   r   #   s    FD '+FJt#*6:J,t3:.2NJ$t+215zC'$.5(,Hj3%,59:+d29-1hsmd*159hsmd2959hsmd29268C=4/615(3-$.548Xc]T18BF)8C=4+?FEI,hsmd.BIEI,hsmd.BIBF)8C=4+?FEI,hsmd.BIEI,hsmd.BIHL/#1ELKO2HSMD4HOKO2HSMD4HOBF)8C=4+?FMQ4hsmd6JQ59hsmd29268C=4/6-1hsmd*159:+d2959hsmd2915(3-$.5.2t2/3337#TD[748$dTk8-1M:#d*1*.J
S 4'. 48c)D07GK.0DKRV98C=4;OV6:J,t3:JN18C=43GN =hsmd>R  >B$hsmd&:A"&OS4Z&'"  #@ #04tNQTXj	 rU   r   c            ;       (    e Zd ZU dZeed<   dddedddddddddddddddddddddddeez  d	e	dz  d
ededz  dedz  de
dz  dedz  dedz  dee   dz  de	deez  deez  dz  deez  dz  dedz  dee   dz  dedz  deez  dz  dedz  de	ed   z  dedz  de	deeef   dz  deeef   dz  d e
dz  d!e
dz  d"e
dz  d#e
d$e	d%df: fd&Zd'ed%edz  fd(Zd%e	fd)Zded	e	dz  de
dz  d%efd*Zddddd+dedz  dedz  dee   dz  de
dz  d%ef
d,Z xZS )-	OIDCProxya  OAuth provider that wraps OAuthProxy to provide configuration via an OIDC configuration URL.

    This provider makes it easier to add OAuth protection for any upstream provider
    that is OIDC compliant.

    Example:
        ```python
        from fastmcp import FastMCP
        from fastmcp.server.auth.oidc_proxy import OIDCProxy

        # Simple OIDC based protection
        auth = OIDCProxy(
            config_url="https://oidc.config.url",
            client_id="your-oidc-client-id",
            client_secret="your-oidc-client-secret",
            base_url="https://your.server.url",
        )

        mcp = FastMCP("My Protected Server", auth=auth)
        ```
    oidc_configNFTr   )r   client_secretaudiencerW   token_verifier	algorithmrequired_scopesverify_id_tokenresource_base_url
issuer_urlredirect_pathallowed_client_redirect_urisclient_storagejwt_signing_keytoken_endpoint_auth_methodrequire_authorization_consentconsent_csp_policyforward_resourceextra_authorize_paramsextra_token_params$fallback_access_token_expiry_seconds%fallback_refresh_token_expiry_seconds#fastmcp_access_token_expiry_secondstoken_expiry_threshold_secondsenable_cimdrV   r   	client_idrp   rq   rW   rr   rs   rt   ru   base_urlrv   rw   rx   ry   rz   r{   r|   r}   )rememberexternalr~   r   r   r   r   r   r   r   r   rA   c                   |st        d      |st        d      |s|st        d      |st        d      ||t        d      |	t        d      t        |t              rt        |      }| j	                  |||      | _        | j
                  j                  r| j
                  j                  s-t        j                  d| j
                          t        d	      | j
                  j                  rt        | j
                  j                        nd}|!|
r|n|}|
rdn|	}| j                  ||||
      }i dt        | j
                  j                        dt        | j
                  j                        d|d|d|d|d|d|d|xs |d| j
                  j                  d|d|d|d|d|d|d||||||d} |r|| d<   i }!i }"|r
||!d<   ||"d<   |r|!j                  |       |r|"j                  |       |!r|!| d<   |"r|"| d <   t        #| <  d!i |  |
| _        |
r|	r|	| _        | j%                  |	       yyy)"u  Initialize the OIDC proxy provider.

        Args:
            config_url: URL of upstream configuration
            strict: Optional strict flag for the configuration
            client_id: Client ID registered with upstream server
            client_secret: Client secret for upstream server. Optional for PKCE public
                clients or when using alternative credentials. When omitted,
                jwt_signing_key must be provided.
            audience: Audience for upstream server
            timeout_seconds: Timeout, in seconds, for the OIDC discovery request
                made during construction. Defaults to 10 seconds so a slow or
                unreachable issuer cannot block server startup indefinitely. Pass
                None to fall back to the HTTP client's own default timeout.
            token_verifier: Optional custom token verifier (e.g., IntrospectionTokenVerifier for opaque tokens).
                If not provided, a JWTVerifier will be created using the OIDC configuration.
                Cannot be used with algorithm or required_scopes parameters (configure these on your verifier instead).
            algorithm: Token verifier algorithm (only used if token_verifier is not provided)
            required_scopes: Required scopes for token validation (only used if token_verifier is not provided)
            verify_id_token: If True, verify the OIDC id_token instead of the access_token.
                Useful for providers that issue opaque (non-JWT) access tokens, since the
                id_token is always a standard JWT verifiable via the provider's JWKS.
            base_url: Public URL where OAuth endpoints will be accessible (includes any mount path)
            resource_base_url: Optional public base URL for the protected resource metadata
                and token audience. Defaults to ``base_url``.
            issuer_url: Issuer URL for OAuth metadata (defaults to base_url). Use root-level URL
                to avoid 404s during discovery when mounting under a path.
            redirect_path: Redirect path configured in upstream OAuth app (defaults to "/auth/callback")
            allowed_client_redirect_uris: List of allowed redirect URI patterns for MCP clients.
                Patterns support wildcards (e.g., "http://localhost:*", "https://*.example.com/*").
                If None (default), DCR clients use registered redirect URIs, with loopback
                ports allowed to vary for MCP compatibility. Unsafe browser schemes are rejected.
                If empty list, no redirect URIs are allowed.
                These are for MCP clients performing loopback redirects, NOT for the upstream OAuth app.
            client_storage: Storage backend for OAuth state (client registrations, encrypted tokens).
                If None, an encrypted file store will be created in the data directory
                (derived from `platformdirs`).
            jwt_signing_key: Secret for signing FastMCP JWT tokens (any string or bytes). If bytes are provided,
                they will be used as is. If a string is provided, it will be derived into a 32-byte key. If not
                provided, the upstream client secret will be used to derive a 32-byte key using PBKDF2.
            token_endpoint_auth_method: Token endpoint authentication method for upstream server.
                Common values: "client_secret_basic", "client_secret_post", "none".
                If None, authlib will use its default (typically "client_secret_basic").
            require_authorization_consent: Whether to require user consent before authorizing clients (default True).
                When True, users see a consent screen before being redirected to the upstream IdP.
                When False, authorization proceeds directly without user confirmation.
                When "external", the built-in consent screen is skipped but no warning is
                logged, indicating that consent is handled externally (e.g. by the upstream IdP).
                SECURITY WARNING: Only set to False for local development or testing environments.
            consent_csp_policy: Content Security Policy for the consent page.
                If None (default), uses the built-in CSP policy with appropriate directives.
                If empty string "", disables CSP entirely (no meta tag is rendered).
                If a non-empty string, uses that as the CSP policy value.
            extra_authorize_params: Additional parameters to forward to the upstream authorization endpoint.
                Useful for provider-specific parameters like prompt=consent or access_type=offline.
                Example: {"prompt": "consent", "access_type": "offline"}
            extra_token_params: Additional parameters to forward to the upstream token endpoint.
                Useful for provider-specific parameters during token exchange.
            fallback_access_token_expiry_seconds: Expiry time to use when upstream provider
                doesn't return `expires_in` in the token response. If not set, uses smart
                defaults: 1 hour if a refresh token is available (since we can refresh),
                or 1 year if no refresh token (for API-key-style tokens like GitHub OAuth Apps).
            fallback_refresh_token_expiry_seconds: Expiry time to use when upstream provider
                doesn't return `refresh_expires_in` (e.g. Cognito, GitHub, many OIDC IdPs).
                Defaults to 1 year. The actual upstream refresh remains the source of
                truth — if upstream rejects the refresh, the client gets `invalid_grant`
                and re-auths.
            fastmcp_access_token_expiry_seconds: Lifetime for the FastMCP-issued access
                token (JWT), decoupling it from the upstream provider's `expires_in`. By
                default (None) the FastMCP access token mirrors the upstream access token
                lifetime. The FastMCP JWT is a reference token re-validated against upstream
                on every request, so a longer FastMCP lifetime does not extend upstream
                access — a revoked or expired upstream session still fails validation. Set
                this for bridges whose upstream issues short-lived access tokens that some
                MCP clients can't refresh gracefully (e.g. `mcp-remote`).
            token_expiry_threshold_seconds: Number of seconds before actual expiry to consider
                a token as expired (default 0). Prevents race conditions where a token
                passes the expiry check but expires before the next operation completes.
            enable_cimd: Whether to enable CIMD (Client ID Metadata Document) client support.
                When True, clients can use their metadata document URL as client_id instead of
                Dynamic Client Registration. Default is True.
        zMissing required config URLzMissing required client idzEither client_secret or jwt_signing_key must be provided. jwt_signing_key is required when client_secret is omitted (e.g., for PKCE public clients).zMissing required base URLNzzCannot specify 'algorithm' when providing a custom token_verifier. Configure the algorithm on your token verifier instead.zCannot specify 'required_scopes' when providing a custom token_verifier. Configure required scopes on your token verifier instead.zInvalid OIDC Configuration: zMissing required OIDC endpointsrs   rq   rt   rW   upstream_authorization_endpointupstream_token_endpointupstream_client_idupstream_client_secretupstream_revocation_endpointrr   r   rv   rw   service_documentation_urlry   rz   r{   r|   r}   r~   r   )r   r   r   r   r   rx   rq   r   r   rl   )rI   rJ   rR   r   rd   ro   r   r   rG   debugr7   get_token_verifierr.   updatesuper__init___verify_id_tokenrt   update_default_scopes)$rO   rV   r   r   rp   rq   rW   rr   rs   rt   ru   r   rv   rw   rx   ry   rz   r{   r|   r}   r~   r   r   r   r   r   r   r   r   r7   verifier_audienceverifier_scopesinit_kwargsfinal_authorize_paramsfinal_token_params	__class__s$                                      rP   r   zOIDCProxy.__init__   sC   ~ :;;9::_3  899 %$ N  * P 
 j#&#J/J66
   77##22LL78H8H7IJK>?? 33   445 	 ! .=	(&5d?O!44#* / /	 5 N*
-s  770*
 &s4+;+;+J+J'K	*

 !)*
 %m*
 +,?*
 n*
 *
  !2*
 *0*
 ()9)9)O)O*
 +,H*
 n*
 *
  )*D!*
" ,-J#*
$ !"4%*
&  0'*
( 5Y5Z3V.L&1*
6 +8K( 24-/19":.-5z*!"))*@A%%&89!4JK010BK,-';' / #2D &&7  /?rU   upstream_token_setc                     | j                   r4|j                  j                  d      }|t        j	                  d       |S |j
                  S )zGet the token to verify from the upstream token set.

        When verify_id_token is enabled, returns the id_token from the
        upstream token response instead of the access_token.
        id_tokenzKverify_id_token is enabled but no id_token found in upstream token response)r   raw_token_datar[   rG   warningaccess_token)rO   r   r   s      rP   _get_verification_tokenz!OIDCProxy._get_verification_token  sM       )88<<ZHH/ O!...rU   c                     | j                   S )a  Return True when id_token verification is enabled.

        This ensures ``load_access_token`` always patches the validated
        result with upstream scopes, even when the IdP issues the same
        JWT for both ``access_token`` and ``id_token``.
        )r   )rO   s    rP   _uses_alternate_verificationz&OIDCProxy._uses_alternate_verification  s     $$$rU   c                 2    t         j                  |||      S )a  Gets the OIDC configuration for the specified configuration URL.

        Args:
            config_url: The OIDC configuration URL
            strict: The strict flag for the configuration
            timeout_seconds: HTTP request timeout in seconds
        )r   rW   )r   rd   )rO   rV   r   rW   s       rP   rd   z OIDCProxy.get_oidc_configuration  s#     !77v 8 
 	
rU   r   c                    t        t        | j                  j                        t        | j                  j                        |||      S )aX  Creates the token verifier for the specified OIDC configuration and arguments.

        Args:
            algorithm: Optional token verifier algorithm
            audience: Optional token verifier audience
            required_scopes: Optional token verifier required_scopes
            timeout_seconds: HTTP request timeout in seconds
        )r   r   rs   rq   rt   )r   rR   ro   r   r   )rO   rs   rq   rt   rW   s        rP   r   zOIDCProxy.get_token_verifier  sB      ))223t''../+
 	
rU   )re   rf   rg   rh   r   ri   &DEFAULT_OIDC_DISCOVERY_TIMEOUT_SECONDSr   rR   rS   rk   r   listr   bytesr   dictr   r   r   r   rd   r   __classcell__)r   s   @rP   rn   rn      s   , #" # %)#&L/3 $,0 % 6:.2$(9=/3.215PT)-!%8<48;?<@:>./ W|8 $	|8
 t|8 |8 Tz|8 *|8 t|8 &,|8 :|8 cT)|8 |8" s"#|8$ &+d2%|8& $t+'|8( Tz)|8, '+3i$&6-|8. &,/|82 ut+3|86 %($J7|8: (,g6L.M'M;|8<  $J=|8> ?|8B !%S#X 5C|8D !cNT1E|8H /2DjI|8J 03TzK|8N .14ZO|8R ),S|8V W|8X 
Y|8|/"2/	t/$%d %

 t
 t	

 

( !%#,0&*
 :
 *	

 cT)
 t
 

rU   rn   )rh   collections.abcr   typingr   r   rZ   key_value.aio.protocolsr   pydanticr   r   r	   typing_extensionsr
   fastmcp.server.authr   fastmcp.server.auth.oauth_proxyr   &fastmcp.server.auth.oauth_proxy.modelsr   !fastmcp.server.auth.providers.jwtr   fastmcp.utilities.loggingr   re   rG   r   r   rn   rl   rU   rP   <module>r      s_   	 %   1 ; ; " - 6 C 9 0	H	 *, &N	 NbY

 Y
rU   