Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
oauth_provider.py131 linesDownload Raw Back to flask_security
1"""2    flask_security.oauth_provider3    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~4 5    Class and methods to create providers for oauth_glue.6    Example providers for github and google.7 8    :copyright: (c) 2024-2024 by J. Christopher Wagner (jwag).9    :license: MIT, see LICENSE for more details.10 11"""12 13from __future__ import annotations14import collections.abc as cabc15import sys16 17try:18    from authlib.integrations.flask_client import OAuth19    from authlib.integrations.base_client.errors import (20        OAuthError,21    )22except ImportError:  # pragma: no cover23    pass24 25import typing as t26 27from flask import redirect28 29from .utils import (30    config_value as cv,31    do_flash,32    get_message,33    get_url,34    url_for_security,35)36 37if t.TYPE_CHECKING:  # pragma: no cover38    from flask.typing import ResponseValue39 40if sys.version_info >= (3, 9):41    OauthCbType = cabc.Callable[["OAuth", t.Any], tuple[str, t.Any]]42else:43    OauthCbType = t.Callable[["OAuth", t.Any], t.Tuple[str, t.Any]]  # pragma: no cover44 45 46class FsOAuthProvider:47    """48    Subclass this or instantiate to add new oauth providers.49 50    Subclassing allows for customizing additional aspects of the oauth flow51    in particular - a custom error path for oauth flow state mismatches and52    other errors thrown by authlib.53 54    Call security.oauthglue.register_provider_ext(myproviderclass("myprovider"))55 56    :param name: a name for provider - must match what was passed if this57     is already registered with Oauth.58    :param registration_info: This dict is passed directly to Oauth as59     part of registration - not needed if provider already registered with60     Oauth61    :param fetch_identity_cb: Call back from response to oauth flow.62    """63 64    def __init__(65        self,66        name: str,67        registration_info: dict[str, t.Any] | None = None,68        fetch_identity_cb: OauthCbType | None = None,69    ):70        self.name = name71        self._registration_info = registration_info or {}72        self._fetch_identity_cb = fetch_identity_cb73 74    def authlib_config(self) -> dict[str, t.Any]:75        """Return dict with authlib configuration.76        This is called as part of provider registration."""77        return self._registration_info78 79    def fetch_identity_cb(self, oauth: OAuth, token: t.Any) -> tuple[str, t.Any]:80        """This callback is called when the oauth81        redirect happens. It must take the response from the provider and return82        a tuple of <user_model_field_name, value> - which will be used83        to look up the user in the datastore."""84        if not self._fetch_identity_cb:  # pragma no cover85            raise NotImplementedError86        return self._fetch_identity_cb(oauth, token)87 88    def oauth_response_failure(self, e: OAuthError) -> ResponseValue:89        """Called if authlib authorize_access_token throws an error.90 91        N.B. flashing doesn't seem to work in some cases - if the session92        cookie has samesite='strict' and it is the first registration.93        """94        m, c = get_message(95            "OAUTH_HANDSHAKE_ERROR", exerror=e.error, exdesc=e.description96        )97        if cv("REDIRECT_BEHAVIOR") == "spa":98            return redirect(get_url(cv("LOGIN_ERROR_VIEW"), qparams={c: m}))99        do_flash(m, c)100        return redirect(url_for_security("login"))101 102 103class GitHubFsOauthProvider(FsOAuthProvider):104    def authlib_config(self):105        return dict(106            access_token_url="https://github.com/login/oauth/access_token",107            access_token_params=None,108            authorize_url="https://github.com/login/oauth/authorize",109            authorize_params=None,110            api_base_url="https://api.github.com/",111            client_kwargs={"scope": "user:email"},112        )113 114    def fetch_identity_cb(self, oauth, token):115        resp = oauth.github.get("user", token=token)116        profile = resp.json()117        return "email", profile["email"]118 119 120class GoogleFsOauthProvider(FsOAuthProvider):121    def authlib_config(self):122        return dict(123            server_metadata_url="https://accounts.google.com/"124            ".well-known/openid-configuration",125            client_kwargs={"scope": "openid email profile"},126        )127 128    def fetch_identity_cb(self, oauth, token):  # pragma no cover129        profile = token["userinfo"]130        return "email", profile["email"]131 
codekingpro/portable-devtools · Team Ai