11import datetime
22import os
33import sys
4+ import uuid
45from functools import wraps
56
67from flask import Response , _request_ctx_stack , redirect , request
78
89from descope .descope_client import DescopeClient
10+ from descope .exceptions import ERROR_TYPE_INVALID_ARGUMENT
911
1012dir_name = os .path .dirname (__file__ )
1113sys .path .insert (0 , os .path .join (dir_name , "../" ))
@@ -92,7 +94,7 @@ def decorated(*args, **kwargs):
9294 return decorator
9395
9496
95- def descope_validate_auth (descope_client , permissions = [], tenant = "" ):
97+ def descope_validate_auth (descope_client , permissions = [], roles = [], tenant = "" ):
9698 """
9799 Test if Access Token is valid
98100 """
@@ -124,6 +126,17 @@ def decorated(*args, **kwargs):
124126 if not valid_permissions :
125127 return Response ("Access denied" , 401 )
126128
129+ if roles :
130+ if tenant :
131+ valid_roles = descope_client .validate_tenant_roles (
132+ jwt_response , roles
133+ )
134+ else :
135+ valid_roles = descope_client .validate_roles (jwt_response , roles )
136+
137+ if not valid_roles :
138+ return Response ("Access denied" , 401 )
139+
127140 # Save the claims on the context execute the original API
128141 _request_ctx_stack .top .claims = jwt_response
129142 response = f (* args , ** kwargs )
@@ -369,6 +382,7 @@ def decorator(f):
369382 def decorated (* args , ** kwargs ):
370383 cookies = request .cookies .copy ()
371384 refresh_token = cookies .get (REFRESH_SESSION_COOKIE_NAME )
385+ cookie_domain = request .headers .get ("Host" , "" )
372386 try :
373387 descope_client .logout (refresh_token )
374388 except AuthException as e :
@@ -378,7 +392,9 @@ def decorated(*args, **kwargs):
378392 response = f (* args , ** kwargs )
379393
380394 # Invalidate all cookies
381- cookies .clear ()
395+ if cookie_domain :
396+ response .delete_cookie (SESSION_COOKIE_NAME , "/" , cookie_domain )
397+ response .delete_cookie (REFRESH_SESSION_COOKIE_NAME , "/" , cookie_domain )
382398 return response
383399
384400 return decorated
@@ -410,3 +426,49 @@ def decorated(*args, **kwargs):
410426 return decorated
411427
412428 return decorator
429+
430+
431+ def descope_full_login (project_id , flow_id , success_redirect_url ):
432+ """
433+ Descope Flow login
434+ """
435+
436+ def decorator (f ):
437+ @wraps (f )
438+ def decorated (* args , ** kwargs ):
439+ id = f"descope-{ uuid .uuid4 ()} "
440+ if not success_redirect_url :
441+ raise AuthException (
442+ 500 ,
443+ ERROR_TYPE_INVALID_ARGUMENT ,
444+ "Missing success_redirect_url parameter" ,
445+ )
446+
447+ html = f"""<!DOCTYPE html>
448+ <html lang="en">
449+ <head>
450+ <script src="https://unpkg.com/@descope/web-component/dist/index.js"></script>
451+ </head>
452+
453+ <body>
454+ <descope-wc id="{ id } " project-id="{ project_id } " flow-id="{ flow_id } "></descope-wc>
455+ <script>
456+ const setCookie = (cookieName, cookieValue, maxAge, path, domain) => {{
457+ document.cookie = cookieName + '=' + cookieValue + ';max-age=' + maxAge + ';path=' + path + ';domain=' + domain + '; samesite=strict; secure;'
458+ }}
459+ const descopeWcEle = document.getElementById('{ id } ');
460+ descopeWcEle.addEventListener('success', async (e) => {{
461+ setCookie('{ SESSION_COOKIE_NAME } ', e.detail.sessionJwt, e.detail.cookieMaxAge, e.detail.cookiePath, e.detail.cookieDomain)
462+ setCookie('{ REFRESH_SESSION_COOKIE_NAME } ', e.detail.refreshJwt, e.detail.cookieMaxAge, e.detail.cookiePath, e.detail.cookieDomain)
463+
464+ document.location.replace("{ success_redirect_url } ")
465+ }});
466+ </script>
467+ </body>
468+ </html>"""
469+ f (* args , ** kwargs )
470+ return html
471+
472+ return decorated
473+
474+ return decorator
0 commit comments