o
    i)                     @  s   d Z ddlmZ ddlZddlZddlmZ ddlZddlm	Z	m
Z
mZ ddlmZmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZ eeZG dd deZG dd deZdS )a!  OAuth 2.0 Token Introspection (RFC 7662) provider for FastMCP.

This module provides token verification for opaque tokens using the OAuth 2.0
Token Introspection protocol defined in RFC 7662. It allows FastMCP servers to
validate tokens issued by authorization servers that don't use JWT format.

Example:
    ```python
    from fastmcp import FastMCP
    from fastmcp.server.auth.providers.introspection import IntrospectionTokenVerifier

    # Verify opaque tokens via RFC 7662 introspection
    verifier = IntrospectionTokenVerifier(
        introspection_url="https://auth.example.com/oauth/introspect",
        client_id="your-client-id",
        client_secret="your-client-secret",
        required_scopes=["read", "write"]
    )

    mcp = FastMCP("My Protected Server", auth=verifier)
    ```
    )annotationsN)Any)
AnyHttpUrl	SecretStrfield_validator)BaseSettingsSettingsConfigDict)AccessTokenTokenVerifier)ENV_FILEparse_scopes)
get_logger)NotSetNotSetTc                   @  s   e Zd ZU dZededdZdZded< dZ	ded< dZ
d	ed
< dZded< dZded< dZded< edddedd ZdS )"IntrospectionTokenVerifierSettingsz8Settings for OAuth 2.0 Token Introspection verification."FASTMCP_SERVER_AUTH_INTROSPECTION_ignore)
env_prefixenv_fileextraNz
str | Noneintrospection_url	client_idzSecretStr | Noneclient_secret
   inttimeout_secondszlist[str] | Nonerequired_scopeszAnyHttpUrl | str | Nonebase_urlbefore)modec                 C  s   t |S )Nr   )clsv r#   q/var/www/html/karishye-ai-python/venv/lib/python3.10/site-packages/fastmcp/server/auth/providers/introspection.py_parse_scopes;   s   z0IntrospectionTokenVerifierSettings._parse_scopes)__name__
__module____qualname____doc__r   r   model_configr   __annotations__r   r   r   r   r   r   classmethodr%   r#   r#   r#   r$   r   +   s    
 
r   c                      sP   e Zd ZdZeeeeeedd fddZdddZdddZdddZ  Z	S ) IntrospectionTokenVerifiera  
    OAuth 2.0 Token Introspection verifier (RFC 7662).

    This verifier validates opaque tokens by calling an OAuth 2.0 token introspection
    endpoint. Unlike JWT verification which is stateless, token introspection requires
    a network call to the authorization server for each token validation.

    The verifier authenticates to the introspection endpoint using HTTP Basic Auth
    with the provided client_id and client_secret, as specified in RFC 7662.

    Use this when:
    - Your authorization server issues opaque (non-JWT) tokens
    - You need to validate tokens from Auth0, Okta, Keycloak, or other OAuth servers
    - Your tokens require real-time revocation checking
    - Your authorization server supports RFC 7662 introspection

    Example:
        ```python
        verifier = IntrospectionTokenVerifier(
            introspection_url="https://auth.example.com/oauth/introspect",
            client_id="my-service",
            client_secret="secret-key",
            required_scopes=["api:read"]
        )
        ```
    r   r   r   r   r   r   r   str | NotSetTr   r   r   int | NotSetTr   list[str] | NotSetT | Noner   !AnyHttpUrl | str | NotSetT | Nonec             
     s   t dd ||||||d D }|jstd|js!td|js(tdt j|j	|j
d |j| _|j| _|j | _|j| _tt| _dS )	a"  
        Initialize the introspection token verifier.

        Args:
            introspection_url: URL of the OAuth 2.0 token introspection endpoint
            client_id: OAuth client ID for authenticating to the introspection endpoint
            client_secret: OAuth client secret for authenticating to the introspection endpoint
            timeout_seconds: HTTP request timeout in seconds (default: 10)
            required_scopes: Required scopes for all tokens (optional)
            base_url: Base URL for TokenVerifier protocol
        c                 S  s   i | ]\}}|t ur||qS r#   )r   ).0kr"   r#   r#   r$   
<dictcomp>s   s
    	z7IntrospectionTokenVerifier.__init__.<locals>.<dictcomp>r.   zhintrospection_url is required - set via parameter or FASTMCP_SERVER_AUTH_INTROSPECTION_INTROSPECTION_URLzXclient_id is required - set via parameter or FASTMCP_SERVER_AUTH_INTROSPECTION_CLIENT_IDz`client_secret is required - set via parameter or FASTMCP_SERVER_AUTH_INTROSPECTION_CLIENT_SECRET)r   r   N)r   model_validateitemsr   
ValueErrorr   r   super__init__r   r   get_secret_valuer   r   r&   logger)selfr   r   r   r   r   r   settings	__class__r#   r$   r:   ]   s@   z#IntrospectionTokenVerifier.__init__returnstrc                 C  s2   | j  d| j }t|dd}d| S )z<Create HTTP Basic Auth header value from client credentials.:zutf-8zBasic )r   r   base64	b64encodeencodedecode)r=   credentialsencodedr#   r#   r$   _create_basic_auth_header   s   
z4IntrospectionTokenVerifier._create_basic_auth_headerintrospection_responsedict[str, Any]	list[str]c                 C  sN   | d}|du rg S t|trdd | D S t|tr%dd |D S g S )z
        Extract scopes from introspection response.

        RFC 7662 allows scopes to be returned as either:
        - A space-separated string in the 'scope' field
        - An array of strings in the 'scope' field (less common but valid)
        scopeNc                 S  s   g | ]
}|  r|  qS r#   )stripr3   sr#   r#   r$   
<listcomp>   s    z>IntrospectionTokenVerifier._extract_scopes.<locals>.<listcomp>c                 S  s   g | ]}|rt |qS r#   )rB   rP   r#   r#   r$   rR      s    )get
isinstancerB   splitlist)r=   rK   scope_valuer#   r#   r$   _extract_scopes   s   


z*IntrospectionTokenVerifier._extract_scopestokenAccessToken | Nonec              
     s`  zt j| jd4 I dH }|  }|j| j|dd|ddddI dH }|jd	krJ| jd
|j|j	r:|j	dd	 nd 	 W d  I dH  W dS |
 }|ddsg| jd 	 W d  I dH  W dS |dpq|dd}|d}|r|t k r| jd| 	 W d  I dH  W dS | |}| jrt|}	t| j}
|
|	s| jd|	|
 	 W d  I dH  W dS t|t|||rt|nd|dW  d  I dH  W S 1 I dH sw   Y  W dS  t jy   | jd| j Y dS  t jy } z| jd| W Y d}~dS d}~w ty/ } z| jd| W Y d}~dS d}~ww )a  
        Verify a bearer token using OAuth 2.0 Token Introspection (RFC 7662).

        This method makes a POST request to the introspection endpoint with the token,
        authenticated using HTTP Basic Auth with the client credentials.

        Args:
            token: The opaque token string to validate

        Returns:
            AccessToken object if valid and active, None if invalid, inactive, or expired
        )timeoutNaccess_token)rY   token_type_hintz!application/x-www-form-urlencodedzapplication/json)AuthorizationzContent-TypeAccept)dataheaders   z(Token introspection failed: HTTP %d - %s activeFz)Token introspection returned active=falser   subunknownexpz4Token validation failed: expired token for client %sz4Token missing required scopes. Has: %s, Required: %s)rY   r   scopes
expires_atclaimsz.Token introspection timed out after %d secondsz&Token introspection request failed: %szToken introspection error: %s)httpxAsyncClientr   rJ   postr   status_coder<   debugtextjsonrS   timerX   r   setissubsetr	   rB   r   TimeoutExceptionRequestError	Exception)r=   rY   clientauth_headerresponseintrospection_datar   rg   rh   token_scopesr   er#   r#   r$   verify_token   s   
"


2

A4Iz'IntrospectionTokenVerifier.verify_token)r   r/   r   r/   r   r/   r   r0   r   r1   r   r2   )rA   rB   )rK   rL   rA   rM   )rY   rB   rA   rZ   )
r&   r'   r(   r)   r   r:   rJ   rX   r~   __classcell__r#   r#   r?   r$   r-   A   s    
>
r-   )r)   
__future__r   rD   rr   typingr   rk   pydanticr   r   r   pydantic_settingsr   r   fastmcp.server.authr	   r
   fastmcp.settingsr   fastmcp.utilities.authr   fastmcp.utilities.loggingr   fastmcp.utilities.typesr   r   r&   r<   r   r-   r#   r#   r#   r$   <module>   s     