
    Gii                        S r SSKJr  SSKrSSKrSSKJr  SSKrSSKr	SSK
r
SSK
Jr  SS jrSS jrSS jrSS	 jrSS
 jrSS jrSS jrSS jrSS jrSS jrg)u8  
auth.py
-------
Auth0 login guard para apps Streamlit.

Flujo:
- Si no hay usuario en session_state:
  - Si viene callback (code + state), intercambia por tokens
  - Si no, construye URL de login y pide iniciar sesión
- Valida roles desde:
  - access token (si viene en claim) o
  - /userinfo + claim de roles
    )annotationsN)	urlencode)PyJWKClientc                 x    S[         R                  ;  a  [        S5      e[        [         R                  S   5      $ )Nauth0zCFalta [auth0] en secrets de Streamlit Cloud (o secrets.toml local).)stsecretsKeyErrordict     RC:\Users\julio\OneDrive\Documentos\Trabajo\Ideas Frescas\Proyectos\Cabanna\auth.py_cfgr      s.    bjj \]]

7#$$r   c                 :    [        5       S   R                  S5      $ )Nredirect_uri/)r   rstripr   r   r   	_base_urlr      s    6.!((--r   c                     [        5       n U S   nU S   n[        5       n[        R                  " S5      nU[        R
                  S'   SUUSUS.nU R                  S5      nU(       a  XeS'   S	U S
[        U5       3$ )Ndomain	client_id   oauth_statecodezopenid profile email)response_typer   r   scopestateaudiencehttps://z/authorize?)r   r   r	   token_urlsafer   session_stategetr   )cfgr   r   r   r   paramsr   s          r   build_login_urlr%   %   s    
&C]FK I;L!!"%E&+B]#  $'F wwz"H%zfX[6):(;<<r   c                    [        5       nUS   nUS   nUS   n[        5       nSU S3nSUUU US.n[        R                  " XgSS	9nUR	                  5         UR                  5       $ )
Nr   r   client_secretr   z/oauth/tokenauthorization_code)
grant_typer   r'   r   r      )jsontimeout)r   r   requestspostraise_for_statusr+   )	r   r#   r   r   r'   r   	token_urlpayloadrs	            r   _exchange_code_for_tokensr3   @   sz    
&C]FK I(M;L6(,/I*&$G 	ir:A668Or   c                    [        5       nUS   n[        R                  " SU S3SSU  30SS9nUR                  5         UR	                  5       $ )Nr   r   z	/userinfoAuthorizationzBearer r*   )headersr,   )r   r-   r"   r/   r+   )access_tokenr#   r   r2   s       r   _fetch_userinfor8   T   sW    
&C]F
6()$ GL>":;	A
 668Or   c                ,   [        5       nUS   nUR                  S5      nSU S3n SU S3n[        U5      nUR                  U 5      n[        R
                  " U UR                  S/U(       a  UOSUS[        U5      0S	9nU$ ! [         a    0 s $ f = f)
ut   
Verifica firma RS256 del access_token (si es JWT).
Si access_token no es JWT o falla verificación, regresamos {}.
r   r   r   r   z/.well-known/jwks.jsonRS256N
verify_aud)
algorithmsr   issueroptions)	r   r"   r   get_signing_key_from_jwtjwtdecodekeybool	Exception)	r7   r#   r   r   r=   jwks_url
jwk_clientsigning_keydecodeds	            r   _verify_jwtrI   _   s    
 &C]Fwwz"Hxq!FfX%;< *
 99,G**OOy!)Xt!4>2
  	s   AB BBc                   SnU R                  S5      U R                  U S35      UR                  S5      UR                  U S35      /nU H6  n[        U[        5      (       d  M  U Vs/ s H  n[        U5      PM     sns  $    / $ s  snf )u   
Ajusta aquí según cómo guardas roles:
- Si usas Auth0 RBAC + Add Permissions in Access Token, quizá viene en access_token.
- Si usas custom claim, típicamente:
  "https://ideasfrescas.com.mx/roles": [...]
z!dev-ajifaa3ovgdvp4ty.us.auth0.comrolesz/roles)r"   
isinstanceliststr)claimsuserinfo	namespace
candidatescxs         r   _extract_rolesrU   y   s     4I

7

i['(W	{&)*	J a$%&AqCFA&&  I 's   +B	c                    [         R                  n U R                  S5      nU R                  S5      nU(       a  U(       d  g[         R                  R                  S5      nU(       a  X#:w  a  [         R                  " S5        g[        U5      nUR                  S5      nUR                  S5      nU(       a  [        U5      O0 nU(       a  [        U5      O0 n[        Xx5      n	UR                  S5      =(       d    UR                  S5      UR                  S	5      =(       d    UR                  S	5      U	UUS
.n
U
[         R                  S'   [         R                  R                  5         U
$ )zU
Si la URL trae ?code=...&state=..., procesa callback y setea session_state['user'].
r   r   Nr   u2   State inválido. Intenta iniciar sesión otra vez.r7   id_tokenemailname)rX   rY   rK   r7   rW   user)
r   query_paramsr"   r!   errorr3   rI   r8   rU   clear)qpr   r   expected_statetokensr7   rW   rO   rP   rK   rZ   s              r   handle_callbackra      s    
B66&>DFF7OEu%%))-8N%1
EF&t,F::n-Lzz*%H +7[&BF 1=|,"H6,E g&=&**W*=V$:

6(:$D  $BV OOKr   c                 @    [         R                  R                  S5      $ )NrZ   )r   r!   r"   r   r   r   get_current_userrc      s    ''r   c                 j    [        5       n U S   nU S   n[        5       nUUS.nSU S[        U5       3$ )Nr   r   )r   returnTor   z/v2/logout?)r   r   r   )r#   r   r   	return_tor$   s        r   
logout_urlrg      sM    
&C]FK II F fX[6):(;<<r   )returnr   )rh   rN   )r   rN   rh   r   )r7   rN   rh   r   )rO   r   rP   r   rh   z	list[str])rh   zdict | None)__doc__
__future__r   osr	   urllib.parser   r-   	streamlitr   r@   r   r   r   r%   r3   r8   rI   rU   ra   rc   rg   r   r   r   <module>rn      sW    # 	  "   
 %
.=6(	4&,\(
=r   