fief_client

Fief client for Python.

 1"Fief client for Python."
 2from fief_client.client import (
 3    Fief,
 4    FiefAccessTokenExpired,
 5    FiefAccessTokenInfo,
 6    FiefAccessTokenInvalid,
 7    FiefAccessTokenMissingPermission,
 8    FiefAccessTokenMissingScope,
 9    FiefAsync,
10    FiefError,
11    FiefIdTokenInvalid,
12    FiefRequestError,
13    FiefTokenResponse,
14    FiefUserInfo,
15)
16
17__version__ = "0.16.1"
18
19__all__ = [
20    "Fief",
21    "FiefAsync",
22    "FiefTokenResponse",
23    "FiefAccessTokenInfo",
24    "FiefUserInfo",
25    "FiefError",
26    "FiefAccessTokenExpired",
27    "FiefAccessTokenMissingPermission",
28    "FiefAccessTokenMissingScope",
29    "FiefAccessTokenInvalid",
30    "FiefIdTokenInvalid",
31    "FiefRequestError",
32    "crypto",
33    "pkce",
34    "integrations",
35]
class Fief(fief_client.client.BaseFief):
383class Fief(BaseFief):
384    """Sync Fief authentication client."""
385
386    def __init__(
387        self,
388        base_url: str,
389        client_id: str,
390        client_secret: Optional[str] = None,
391        *,
392        encryption_key: Optional[str] = None,
393        host: Optional[str] = None,
394        verify: VerifyTypes = True,
395        cert: Optional[CertTypes] = None,
396    ) -> None:
397        super().__init__(
398            base_url,
399            client_id,
400            client_secret,
401            encryption_key=encryption_key,
402            host=host,
403            verify=verify,
404            cert=cert,
405        )
406
407    def auth_url(
408        self,
409        redirect_uri: str,
410        *,
411        state: Optional[str] = None,
412        scope: Optional[List[str]] = None,
413        code_challenge: Optional[str] = None,
414        code_challenge_method: Optional[str] = None,
415        lang: Optional[str] = None,
416        extras_params: Optional[Mapping[str, str]] = None,
417    ) -> str:
418        """
419        Return an authorization URL.
420
421        :param redirect_uri: Your callback URI where the user will be redirected after Fief authentication.
422        :param state: Optional string that will be returned back in the callback parameters to allow you to retrieve state information.
423        :param scope: Optional list of scopes to ask for.
424        :param code_challenge: Optional code challenge for
425        [PKCE process](https://docs.fief.dev/going-further/pkce/).
426        :param code_challenge_method: Method used to hash the PKCE code challenge.
427        :param lang: Optional parameter to set the user locale.
428        Should be a valid [RFC 3066](https://www.rfc-editor.org/rfc/rfc3066) language identifier, like `fr` or `pt-PT`.
429        If not provided, the user locale is determined by their browser settings.
430        :param extras_params: Optional dictionary containing [specific parameters](https://docs.fief.dev/going-further/authorize-url/).
431
432        **Example:**
433
434        ```py
435        auth_url = fief.auth_url("http://localhost:8000/callback", scope=["openid"])
436        ```
437        """
438        openid_configuration = self._get_openid_configuration()
439        return self._auth_url(
440            openid_configuration,
441            redirect_uri,
442            state=state,
443            scope=scope,
444            code_challenge=code_challenge,
445            code_challenge_method=code_challenge_method,
446            lang=lang,
447            extras_params=extras_params,
448        )
449
450    def auth_callback(
451        self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None
452    ) -> Tuple[FiefTokenResponse, FiefUserInfo]:
453        """
454        Return a `FiefTokenResponse` and `FiefUserInfo` in exchange of an authorization code.
455
456        :param code: The authorization code.
457        :param redirect_uri: The exact same `redirect_uri` you passed to the authorization URL.
458        :param code_verifier:  The raw
459        [PKCE](https://docs.fief.dev/going-further/pkce/) code used to generate the code challenge during authorization.
460
461        **Example:**
462
463        ```py
464        tokens, userinfo = fief.auth_callback("CODE", "http://localhost:8000/callback")
465        ```
466        """
467        token_response = self._auth_exchange_token(
468            code, redirect_uri, code_verifier=code_verifier
469        )
470        jwks = self._get_jwks()
471        userinfo = self._decode_id_token(
472            token_response["id_token"],
473            jwks,
474            code=code,
475            access_token=token_response.get("access_token"),
476        )
477        return token_response, userinfo
478
479    def auth_refresh_token(
480        self, refresh_token: str, *, scope: Optional[List[str]] = None
481    ) -> Tuple[FiefTokenResponse, FiefUserInfo]:
482        """
483        Return fresh `FiefTokenResponse` and `FiefUserInfo` in exchange of a refresh token
484
485        :param refresh_token: A valid refresh token.
486        :param scope: Optional list of scopes to ask for.
487        If not provided, the access token will share the same list of scopes as requested the first time.
488        Otherwise, it should be a subset of the original list of scopes.
489
490        **Example:**
491
492        ```py
493        tokens, userinfo = fief.auth_refresh_token("REFRESH_TOKEN")
494        ```
495        """
496        token_endpoint = self._get_endpoint_url(
497            self._get_openid_configuration(), "token_endpoint"
498        )
499        with self._get_httpx_client() as client:
500            request = self._get_auth_refresh_token_request(
501                client,
502                endpoint=token_endpoint,
503                refresh_token=refresh_token,
504                scope=scope,
505            )
506            response = client.send(request)
507
508            self._handle_request_error(response)
509
510            token_response = response.json()
511        jwks = self._get_jwks()
512        userinfo = self._decode_id_token(
513            token_response["id_token"],
514            jwks,
515            access_token=token_response.get("access_token"),
516        )
517        return token_response, userinfo
518
519    def validate_access_token(
520        self,
521        access_token: str,
522        *,
523        required_scope: Optional[List[str]] = None,
524        required_permissions: Optional[List[str]] = None,
525    ) -> FiefAccessTokenInfo:
526        """
527        Check if an access token is valid and optionally that it has a required list of scopes,
528        or a required list of [permissions](https://docs.fief.dev/getting-started/access-control/).
529        Returns a `FiefAccessTokenInfo`.
530
531        :param access_token: The access token to validate.
532        :param required_scope: Optional list of scopes to check for.
533        :param required_permissions: Optional list of permissions to check for.
534
535        **Example: Validate access token with required scopes**
536
537        ```py
538        try:
539            access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_scope=["required_scope"])
540        except FiefAccessTokenInvalid:
541            print("Invalid access token")
542        except FiefAccessTokenExpired:
543            print("Expired access token")
544        except FiefAccessTokenMissingScope:
545            print("Missing required scope")
546
547        print(access_token_info)
548        ```
549
550        **Example: Validate access token with required permissions**
551
552        ```py
553        try:
554            access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_permissions=["castles:create", "castles:read"])
555        except FiefAccessTokenInvalid:
556            print("Invalid access token")
557        except FiefAccessTokenExpired:
558            print("Expired access token")
559        except FiefAccessTokenMissingPermission:
560            print("Missing required permission")
561
562        print(access_token_info)
563        ```
564        """
565        jwks = self._get_jwks()
566        return self._validate_access_token(
567            access_token,
568            jwks,
569            required_scope=required_scope,
570            required_permissions=required_permissions,
571        )
572
573    def userinfo(self, access_token: str) -> FiefUserInfo:
574        """
575        Return fresh `FiefUserInfo` from the Fief API using a valid access token.
576
577        :param access_token: A valid access token.
578
579        **Example:**
580
581        ```py
582        userinfo = fief.userinfo("ACCESS_TOKEN")
583        ```
584        """
585        userinfo_endpoint = self._get_endpoint_url(
586            self._get_openid_configuration(), "userinfo_endpoint"
587        )
588        with self._get_httpx_client() as client:
589            request = self._get_userinfo_request(
590                client, endpoint=userinfo_endpoint, access_token=access_token
591            )
592            response = client.send(request)
593
594            self._handle_request_error(response)
595
596            return response.json()
597
598    def update_profile(self, access_token: str, data: Dict[str, Any]) -> FiefUserInfo:
599        """
600        Update user information with the Fief API using a valid access token.
601
602        :param access_token: A valid access token.
603        :param data: A dictionary containing the data to update.
604
605        **Example: Update email address**
606
607        ```py
608        userinfo = fief.update_profile("ACCESS_TOKEN", { "email": "anne@nantes.city" })
609        ```
610
611        **Example: Update password**
612
613        ```py
614        userinfo = fief.update_profile("ACCESS_TOKEN", { "password": "herminetincture" })
615        ```
616
617        **Example: Update user field**
618
619        To update [user field](https://docs.fief.dev/getting-started/user-fields/) values, you need to nest them into a `fields` dictionary, indexed by their slug.
620
621        ```py
622        userinfo = fief.update_profile("ACCESS_TOKEN", { "fields": { "first_name": "Anne" } })
623        ```
624        """
625        update_profile_endpoint = f"{self.base_url}/api/profile"
626
627        with self._get_httpx_client() as client:
628            request = self._get_update_profile_request(
629                client,
630                endpoint=update_profile_endpoint,
631                access_token=access_token,
632                data=data,
633            )
634            response = client.send(request)
635
636            self._handle_request_error(response)
637
638            return response.json()
639
640    def logout_url(self, redirect_uri: str) -> str:
641        """
642        Returns a logout URL. If you redirect the user to this page, Fief will clear the session stored on its side.
643
644        **You're still responsible for clearing your own session mechanism if any.**
645
646        :param redirect_uri: A valid URL where the user will be redirected after the logout process.
647
648        **Example:**
649
650        ```py
651        logout_url = fief.logout_url("http://localhost:8000")
652        ```
653        """
654        params = {"redirect_uri": redirect_uri}
655        return f"{self.base_url}/logout?{urlencode(params)}"
656
657    @contextlib.contextmanager
658    def _get_httpx_client(self):
659        headers = {}
660        if self.host is not None:
661            headers["Host"] = self.host
662
663        with httpx.Client(
664            base_url=self.base_url, headers=headers, verify=self.verify, cert=self.cert
665        ) as client:
666            yield client
667
668    def _get_openid_configuration(self) -> Dict[str, Any]:
669        if self._openid_configuration is not None:
670            return self._openid_configuration
671
672        with self._get_httpx_client() as client:
673            request = self._get_openid_configuration_request(client)
674            response = client.send(request)
675            json = response.json()
676            self._openid_configuration = json
677            return json
678
679    def _get_jwks(self) -> jwk.JWKSet:
680        if self._jwks is not None:
681            return self._jwks
682
683        jwks_uri = self._get_endpoint_url(self._get_openid_configuration(), "jwks_uri")
684        with self._get_httpx_client() as client:
685            response = client.get(jwks_uri)
686            self._jwks = jwk.JWKSet.from_json(response.text)
687            return self._jwks
688
689    def _auth_exchange_token(
690        self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None
691    ) -> FiefTokenResponse:
692        token_endpoint = self._get_endpoint_url(
693            self._get_openid_configuration(), "token_endpoint"
694        )
695        with self._get_httpx_client() as client:
696            request = self._get_auth_exchange_token_request(
697                client,
698                endpoint=token_endpoint,
699                code=code,
700                redirect_uri=redirect_uri,
701                code_verifier=code_verifier,
702            )
703            response = client.send(request)
704
705            self._handle_request_error(response)
706
707            return response.json()

Sync Fief authentication client.

Fief( base_url: str, client_id: str, client_secret: Optional[str] = None, *, encryption_key: Optional[str] = None, host: Optional[str] = None, verify: Union[str, bool, ssl.SSLContext] = True, cert: Union[str, Tuple[str, Optional[str]], Tuple[str, Optional[str], Optional[str]], NoneType] = None)
386    def __init__(
387        self,
388        base_url: str,
389        client_id: str,
390        client_secret: Optional[str] = None,
391        *,
392        encryption_key: Optional[str] = None,
393        host: Optional[str] = None,
394        verify: VerifyTypes = True,
395        cert: Optional[CertTypes] = None,
396    ) -> None:
397        super().__init__(
398            base_url,
399            client_id,
400            client_secret,
401            encryption_key=encryption_key,
402            host=host,
403            verify=verify,
404            cert=cert,
405        )

Initialize the client.

Parameters
  • base_url: Base URL of your Fief tenant.
  • client_id: ID of your Fief client.
  • client_secret: Secret of your Fief client. If you're implementing a desktop app, it's not recommended to use it, since it can be easily found by the end-user in the source code. The recommended way is to use a Public client.
  • encryption_key: Encryption key of your Fief client. Necessary only if ID Token encryption is enabled.
  • **verify: Corresponds to the verify parameter of HTTPX. Useful to customize SSL connection handling.
  • **cert: Corresponds to the cert parameter of HTTPX. Useful to customize SSL connection handling.
def auth_url( self, redirect_uri: str, *, state: Optional[str] = None, scope: Optional[List[str]] = None, code_challenge: Optional[str] = None, code_challenge_method: Optional[str] = None, lang: Optional[str] = None, extras_params: Optional[Mapping[str, str]] = None) -> str:
407    def auth_url(
408        self,
409        redirect_uri: str,
410        *,
411        state: Optional[str] = None,
412        scope: Optional[List[str]] = None,
413        code_challenge: Optional[str] = None,
414        code_challenge_method: Optional[str] = None,
415        lang: Optional[str] = None,
416        extras_params: Optional[Mapping[str, str]] = None,
417    ) -> str:
418        """
419        Return an authorization URL.
420
421        :param redirect_uri: Your callback URI where the user will be redirected after Fief authentication.
422        :param state: Optional string that will be returned back in the callback parameters to allow you to retrieve state information.
423        :param scope: Optional list of scopes to ask for.
424        :param code_challenge: Optional code challenge for
425        [PKCE process](https://docs.fief.dev/going-further/pkce/).
426        :param code_challenge_method: Method used to hash the PKCE code challenge.
427        :param lang: Optional parameter to set the user locale.
428        Should be a valid [RFC 3066](https://www.rfc-editor.org/rfc/rfc3066) language identifier, like `fr` or `pt-PT`.
429        If not provided, the user locale is determined by their browser settings.
430        :param extras_params: Optional dictionary containing [specific parameters](https://docs.fief.dev/going-further/authorize-url/).
431
432        **Example:**
433
434        ```py
435        auth_url = fief.auth_url("http://localhost:8000/callback", scope=["openid"])
436        ```
437        """
438        openid_configuration = self._get_openid_configuration()
439        return self._auth_url(
440            openid_configuration,
441            redirect_uri,
442            state=state,
443            scope=scope,
444            code_challenge=code_challenge,
445            code_challenge_method=code_challenge_method,
446            lang=lang,
447            extras_params=extras_params,
448        )

Return an authorization URL.

Parameters
  • redirect_uri: Your callback URI where the user will be redirected after Fief authentication.
  • state: Optional string that will be returned back in the callback parameters to allow you to retrieve state information.
  • scope: Optional list of scopes to ask for.
  • code_challenge: Optional code challenge for PKCE process.
  • code_challenge_method: Method used to hash the PKCE code challenge.
  • lang: Optional parameter to set the user locale. Should be a valid RFC 3066 language identifier, like fr or pt-PT. If not provided, the user locale is determined by their browser settings.
  • **extras_params: Optional dictionary containing specific parameters.

Example:

auth_url = fief.auth_url("http://localhost:8000/callback", scope=["openid"])
def auth_callback( self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None) -> Tuple[fief_client.FiefTokenResponse, fief_client.FiefUserInfo]:
450    def auth_callback(
451        self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None
452    ) -> Tuple[FiefTokenResponse, FiefUserInfo]:
453        """
454        Return a `FiefTokenResponse` and `FiefUserInfo` in exchange of an authorization code.
455
456        :param code: The authorization code.
457        :param redirect_uri: The exact same `redirect_uri` you passed to the authorization URL.
458        :param code_verifier:  The raw
459        [PKCE](https://docs.fief.dev/going-further/pkce/) code used to generate the code challenge during authorization.
460
461        **Example:**
462
463        ```py
464        tokens, userinfo = fief.auth_callback("CODE", "http://localhost:8000/callback")
465        ```
466        """
467        token_response = self._auth_exchange_token(
468            code, redirect_uri, code_verifier=code_verifier
469        )
470        jwks = self._get_jwks()
471        userinfo = self._decode_id_token(
472            token_response["id_token"],
473            jwks,
474            code=code,
475            access_token=token_response.get("access_token"),
476        )
477        return token_response, userinfo

Return a FiefTokenResponse and FiefUserInfo in exchange of an authorization code.

Parameters
  • code: The authorization code.
  • redirect_uri: The exact same redirect_uri you passed to the authorization URL.
  • code_verifier: The raw PKCE code used to generate the code challenge during authorization.

Example:

tokens, userinfo = fief.auth_callback("CODE", "http://localhost:8000/callback")
def auth_refresh_token( self, refresh_token: str, *, scope: Optional[List[str]] = None) -> Tuple[fief_client.FiefTokenResponse, fief_client.FiefUserInfo]:
479    def auth_refresh_token(
480        self, refresh_token: str, *, scope: Optional[List[str]] = None
481    ) -> Tuple[FiefTokenResponse, FiefUserInfo]:
482        """
483        Return fresh `FiefTokenResponse` and `FiefUserInfo` in exchange of a refresh token
484
485        :param refresh_token: A valid refresh token.
486        :param scope: Optional list of scopes to ask for.
487        If not provided, the access token will share the same list of scopes as requested the first time.
488        Otherwise, it should be a subset of the original list of scopes.
489
490        **Example:**
491
492        ```py
493        tokens, userinfo = fief.auth_refresh_token("REFRESH_TOKEN")
494        ```
495        """
496        token_endpoint = self._get_endpoint_url(
497            self._get_openid_configuration(), "token_endpoint"
498        )
499        with self._get_httpx_client() as client:
500            request = self._get_auth_refresh_token_request(
501                client,
502                endpoint=token_endpoint,
503                refresh_token=refresh_token,
504                scope=scope,
505            )
506            response = client.send(request)
507
508            self._handle_request_error(response)
509
510            token_response = response.json()
511        jwks = self._get_jwks()
512        userinfo = self._decode_id_token(
513            token_response["id_token"],
514            jwks,
515            access_token=token_response.get("access_token"),
516        )
517        return token_response, userinfo

Return fresh FiefTokenResponse and FiefUserInfo in exchange of a refresh token

Parameters
  • refresh_token: A valid refresh token.
  • scope: Optional list of scopes to ask for. If not provided, the access token will share the same list of scopes as requested the first time. Otherwise, it should be a subset of the original list of scopes.

Example:

tokens, userinfo = fief.auth_refresh_token("REFRESH_TOKEN")
def validate_access_token( self, access_token: str, *, required_scope: Optional[List[str]] = None, required_permissions: Optional[List[str]] = None) -> fief_client.FiefAccessTokenInfo:
519    def validate_access_token(
520        self,
521        access_token: str,
522        *,
523        required_scope: Optional[List[str]] = None,
524        required_permissions: Optional[List[str]] = None,
525    ) -> FiefAccessTokenInfo:
526        """
527        Check if an access token is valid and optionally that it has a required list of scopes,
528        or a required list of [permissions](https://docs.fief.dev/getting-started/access-control/).
529        Returns a `FiefAccessTokenInfo`.
530
531        :param access_token: The access token to validate.
532        :param required_scope: Optional list of scopes to check for.
533        :param required_permissions: Optional list of permissions to check for.
534
535        **Example: Validate access token with required scopes**
536
537        ```py
538        try:
539            access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_scope=["required_scope"])
540        except FiefAccessTokenInvalid:
541            print("Invalid access token")
542        except FiefAccessTokenExpired:
543            print("Expired access token")
544        except FiefAccessTokenMissingScope:
545            print("Missing required scope")
546
547        print(access_token_info)
548        ```
549
550        **Example: Validate access token with required permissions**
551
552        ```py
553        try:
554            access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_permissions=["castles:create", "castles:read"])
555        except FiefAccessTokenInvalid:
556            print("Invalid access token")
557        except FiefAccessTokenExpired:
558            print("Expired access token")
559        except FiefAccessTokenMissingPermission:
560            print("Missing required permission")
561
562        print(access_token_info)
563        ```
564        """
565        jwks = self._get_jwks()
566        return self._validate_access_token(
567            access_token,
568            jwks,
569            required_scope=required_scope,
570            required_permissions=required_permissions,
571        )

Check if an access token is valid and optionally that it has a required list of scopes, or a required list of permissions. Returns a FiefAccessTokenInfo.

Parameters
  • access_token: The access token to validate.
  • required_scope: Optional list of scopes to check for.
  • required_permissions: Optional list of permissions to check for.

Example: Validate access token with required scopes

try:
    access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_scope=["required_scope"])
except FiefAccessTokenInvalid:
    print("Invalid access token")
except FiefAccessTokenExpired:
    print("Expired access token")
except FiefAccessTokenMissingScope:
    print("Missing required scope")

print(access_token_info)

Example: Validate access token with required permissions

try:
    access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_permissions=["castles:create", "castles:read"])
except FiefAccessTokenInvalid:
    print("Invalid access token")
except FiefAccessTokenExpired:
    print("Expired access token")
except FiefAccessTokenMissingPermission:
    print("Missing required permission")

print(access_token_info)
def userinfo(self, access_token: str) -> fief_client.FiefUserInfo:
573    def userinfo(self, access_token: str) -> FiefUserInfo:
574        """
575        Return fresh `FiefUserInfo` from the Fief API using a valid access token.
576
577        :param access_token: A valid access token.
578
579        **Example:**
580
581        ```py
582        userinfo = fief.userinfo("ACCESS_TOKEN")
583        ```
584        """
585        userinfo_endpoint = self._get_endpoint_url(
586            self._get_openid_configuration(), "userinfo_endpoint"
587        )
588        with self._get_httpx_client() as client:
589            request = self._get_userinfo_request(
590                client, endpoint=userinfo_endpoint, access_token=access_token
591            )
592            response = client.send(request)
593
594            self._handle_request_error(response)
595
596            return response.json()

Return fresh FiefUserInfo from the Fief API using a valid access token.

Parameters
  • access_token: A valid access token.

Example:

userinfo = fief.userinfo("ACCESS_TOKEN")
def update_profile( self, access_token: str, data: Dict[str, Any]) -> fief_client.FiefUserInfo:
598    def update_profile(self, access_token: str, data: Dict[str, Any]) -> FiefUserInfo:
599        """
600        Update user information with the Fief API using a valid access token.
601
602        :param access_token: A valid access token.
603        :param data: A dictionary containing the data to update.
604
605        **Example: Update email address**
606
607        ```py
608        userinfo = fief.update_profile("ACCESS_TOKEN", { "email": "anne@nantes.city" })
609        ```
610
611        **Example: Update password**
612
613        ```py
614        userinfo = fief.update_profile("ACCESS_TOKEN", { "password": "herminetincture" })
615        ```
616
617        **Example: Update user field**
618
619        To update [user field](https://docs.fief.dev/getting-started/user-fields/) values, you need to nest them into a `fields` dictionary, indexed by their slug.
620
621        ```py
622        userinfo = fief.update_profile("ACCESS_TOKEN", { "fields": { "first_name": "Anne" } })
623        ```
624        """
625        update_profile_endpoint = f"{self.base_url}/api/profile"
626
627        with self._get_httpx_client() as client:
628            request = self._get_update_profile_request(
629                client,
630                endpoint=update_profile_endpoint,
631                access_token=access_token,
632                data=data,
633            )
634            response = client.send(request)
635
636            self._handle_request_error(response)
637
638            return response.json()

Update user information with the Fief API using a valid access token.

Parameters
  • access_token: A valid access token.
  • data: A dictionary containing the data to update.

Example: Update email address

userinfo = fief.update_profile("ACCESS_TOKEN", { "email": "anne@nantes.city" })

Example: Update password

userinfo = fief.update_profile("ACCESS_TOKEN", { "password": "herminetincture" })

Example: Update user field

To update user field values, you need to nest them into a fields dictionary, indexed by their slug.

userinfo = fief.update_profile("ACCESS_TOKEN", { "fields": { "first_name": "Anne" } })
def logout_url(self, redirect_uri: str) -> str:
640    def logout_url(self, redirect_uri: str) -> str:
641        """
642        Returns a logout URL. If you redirect the user to this page, Fief will clear the session stored on its side.
643
644        **You're still responsible for clearing your own session mechanism if any.**
645
646        :param redirect_uri: A valid URL where the user will be redirected after the logout process.
647
648        **Example:**
649
650        ```py
651        logout_url = fief.logout_url("http://localhost:8000")
652        ```
653        """
654        params = {"redirect_uri": redirect_uri}
655        return f"{self.base_url}/logout?{urlencode(params)}"

Returns a logout URL. If you redirect the user to this page, Fief will clear the session stored on its side.

You're still responsible for clearing your own session mechanism if any.

Parameters
  • redirect_uri: A valid URL where the user will be redirected after the logout process.

Example:

logout_url = fief.logout_url("http://localhost:8000")
Inherited Members
fief_client.client.BaseFief
base_url
client_id
client_secret
class FiefAsync(fief_client.client.BaseFief):
 710class FiefAsync(BaseFief):
 711    """Async Fief authentication client."""
 712
 713    def __init__(
 714        self,
 715        base_url: str,
 716        client_id: str,
 717        client_secret: Optional[str] = None,
 718        *,
 719        encryption_key: Optional[str] = None,
 720        host: Optional[str] = None,
 721        verify: VerifyTypes = True,
 722        cert: Optional[CertTypes] = None,
 723    ) -> None:
 724        super().__init__(
 725            base_url,
 726            client_id,
 727            client_secret,
 728            encryption_key=encryption_key,
 729            host=host,
 730            verify=verify,
 731            cert=cert,
 732        )
 733
 734    async def auth_url(
 735        self,
 736        redirect_uri: str,
 737        *,
 738        state: Optional[str] = None,
 739        scope: Optional[List[str]] = None,
 740        code_challenge: Optional[str] = None,
 741        code_challenge_method: Optional[str] = None,
 742        lang: Optional[str] = None,
 743        extras_params: Optional[Mapping[str, str]] = None,
 744    ) -> str:
 745        """
 746        Return an authorization URL.
 747
 748        :param redirect_uri: Your callback URI where the user will be redirected after Fief authentication.
 749        :param state: Optional string that will be returned back in the callback parameters to allow you to retrieve state information.
 750        :param scope: Optional list of scopes to ask for.
 751        :param code_challenge: Optional code challenge for
 752        [PKCE process](https://docs.fief.dev/going-further/pkce/).
 753        :param code_challenge_method: Method used to hash the PKCE code challenge.
 754        :param lang: Optional parameter to set the user locale.
 755        Should be a valid [RFC 3066](https://www.rfc-editor.org/rfc/rfc3066) language identifier, like `fr` or `pt-PT`.
 756        If not provided, the user locale is determined by their browser settings.
 757        :param extras_params: Optional dictionary containing [specific parameters](https://docs.fief.dev/going-further/authorize-url/).
 758
 759        **Example:**
 760
 761        ```py
 762        auth_url = await fief.auth_url("http://localhost:8000/callback", scope=["openid"])
 763        ```
 764        """
 765        openid_configuration = await self._get_openid_configuration()
 766        return self._auth_url(
 767            openid_configuration,
 768            redirect_uri,
 769            state=state,
 770            scope=scope,
 771            code_challenge=code_challenge,
 772            code_challenge_method=code_challenge_method,
 773            lang=lang,
 774            extras_params=extras_params,
 775        )
 776
 777    async def auth_callback(
 778        self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None
 779    ) -> Tuple[FiefTokenResponse, FiefUserInfo]:
 780        """
 781        Return a `FiefTokenResponse` and `FiefUserInfo` in exchange of an authorization code.
 782
 783        :param code: The authorization code.
 784        :param redirect_uri: The exact same `redirect_uri` you passed to the authorization URL.
 785        :param code_verifier:  The raw
 786        [PKCE](https://docs.fief.dev/going-further/pkce/) code used to generate the code challenge during authorization.
 787
 788        **Example:**
 789
 790        ```py
 791        tokens, userinfo = await fief.auth_callback("CODE", "http://localhost:8000/callback")
 792        ```
 793        """
 794        token_response = await self._auth_exchange_token(
 795            code, redirect_uri, code_verifier=code_verifier
 796        )
 797        jwks = await self._get_jwks()
 798        userinfo = self._decode_id_token(
 799            token_response["id_token"],
 800            jwks,
 801            code=code,
 802            access_token=token_response.get("access_token"),
 803        )
 804        return token_response, userinfo
 805
 806    async def auth_refresh_token(
 807        self, refresh_token: str, *, scope: Optional[List[str]] = None
 808    ) -> Tuple[FiefTokenResponse, FiefUserInfo]:
 809        """
 810        Return fresh `FiefTokenResponse` and `FiefUserInfo` in exchange of a refresh token
 811
 812        :param refresh_token: A valid refresh token.
 813        :param scope: Optional list of scopes to ask for.
 814        If not provided, the access token will share the same list of scopes as requested the first time.
 815        Otherwise, it should be a subset of the original list of scopes.
 816
 817        **Example:**
 818
 819        ```py
 820        tokens, userinfo = await fief.auth_refresh_token("REFRESH_TOKEN")
 821        ```
 822        """
 823        token_endpoint = self._get_endpoint_url(
 824            await self._get_openid_configuration(), "token_endpoint"
 825        )
 826        async with self._get_httpx_client() as client:
 827            request = self._get_auth_refresh_token_request(
 828                client,
 829                endpoint=token_endpoint,
 830                refresh_token=refresh_token,
 831                scope=scope,
 832            )
 833            response = await client.send(request)
 834
 835            self._handle_request_error(response)
 836
 837            token_response = response.json()
 838
 839        jwks = await self._get_jwks()
 840        userinfo = self._decode_id_token(
 841            token_response["id_token"],
 842            jwks,
 843            access_token=token_response.get("access_token"),
 844        )
 845        return token_response, userinfo
 846
 847    async def validate_access_token(
 848        self,
 849        access_token: str,
 850        *,
 851        required_scope: Optional[List[str]] = None,
 852        required_permissions: Optional[List[str]] = None,
 853    ) -> FiefAccessTokenInfo:
 854        """
 855        Check if an access token is valid and optionally that it has a required list of scopes,
 856        or a required list of [permissions](https://docs.fief.dev/getting-started/access-control/).
 857        Returns a `FiefAccessTokenInfo`.
 858
 859        :param access_token: The access token to validate.
 860        :param required_scope: Optional list of scopes to check for.
 861        :param required_permissions: Optional list of permissions to check for.
 862
 863        **Example: Validate access token with required scopes**
 864
 865        ```py
 866        try:
 867            access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_scope=["required_scope"])
 868        except FiefAccessTokenInvalid:
 869            print("Invalid access token")
 870        except FiefAccessTokenExpired:
 871            print("Expired access token")
 872        except FiefAccessTokenMissingScope:
 873            print("Missing required scope")
 874
 875        print(access_token_info)
 876        ```
 877
 878        **Example: Validate access token with required permissions**
 879
 880        ```py
 881        try:
 882            access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_permissions=["castles:create", "castles:read"])
 883        except FiefAccessTokenInvalid:
 884            print("Invalid access token")
 885        except FiefAccessTokenExpired:
 886            print("Expired access token")
 887        except FiefAccessTokenMissingPermission:
 888            print("Missing required permission")
 889
 890        print(access_token_info)
 891        ```
 892        """
 893        jwks = await self._get_jwks()
 894        return self._validate_access_token(
 895            access_token,
 896            jwks,
 897            required_scope=required_scope,
 898            required_permissions=required_permissions,
 899        )
 900
 901    async def userinfo(self, access_token: str) -> FiefUserInfo:
 902        """
 903        Return fresh `FiefUserInfo` from the Fief API using a valid access token.
 904
 905        :param access_token: A valid access token.
 906
 907        **Example:**
 908
 909        ```py
 910        userinfo = await fief.userinfo("ACCESS_TOKEN")
 911        ```
 912        """
 913        userinfo_endpoint = self._get_endpoint_url(
 914            await self._get_openid_configuration(), "userinfo_endpoint"
 915        )
 916        async with self._get_httpx_client() as client:
 917            request = self._get_userinfo_request(
 918                client, endpoint=userinfo_endpoint, access_token=access_token
 919            )
 920            response = await client.send(request)
 921
 922            self._handle_request_error(response)
 923
 924            return response.json()
 925
 926    async def update_profile(
 927        self, access_token: str, data: Dict[str, Any]
 928    ) -> FiefUserInfo:
 929        """
 930        Update user information with the Fief API using a valid access token.
 931
 932        :param access_token: A valid access token.
 933        :param data: A dictionary containing the data to update.
 934
 935        **Example: Update email address**
 936
 937        ```py
 938        userinfo = await fief.update_profile("ACCESS_TOKEN", { "email": "anne@nantes.city" })
 939        ```
 940
 941        **Example: Update password**
 942
 943        ```py
 944        userinfo = await fief.update_profile("ACCESS_TOKEN", { "password": "herminetincture" })
 945        ```
 946
 947        **Example: Update user field**
 948
 949        To update [user field](https://docs.fief.dev/getting-started/user-fields/) values, you need to nest them into a `fields` dictionary, indexed by their slug.
 950
 951        ```py
 952        userinfo = await fief.update_profile("ACCESS_TOKEN", { "fields": { "first_name": "Anne" } })
 953        ```
 954        """
 955        update_profile_endpoint = f"{self.base_url}/api/profile"
 956
 957        async with self._get_httpx_client() as client:
 958            request = self._get_update_profile_request(
 959                client,
 960                endpoint=update_profile_endpoint,
 961                access_token=access_token,
 962                data=data,
 963            )
 964            response = await client.send(request)
 965
 966            self._handle_request_error(response)
 967
 968            return response.json()
 969
 970    async def logout_url(self, redirect_uri: str) -> str:
 971        """
 972        Returns a logout URL. If you redirect the user to this page, Fief will clear the session stored on its side.
 973
 974        **You're still responsible for clearing your own session mechanism if any.**
 975
 976        :param redirect_uri: A valid URL where the user will be redirected after the logout process:
 977
 978        **Example:**
 979
 980        ```py
 981        logout_url = await fief.logout_url("http://localhost:8000")
 982        ```
 983        """
 984        params = {"redirect_uri": redirect_uri}
 985        return f"{self.base_url}/logout?{urlencode(params)}"
 986
 987    @contextlib.asynccontextmanager
 988    async def _get_httpx_client(self):
 989        headers = {}
 990        if self.host is not None:
 991            headers["Host"] = self.host
 992
 993        async with httpx.AsyncClient(
 994            base_url=self.base_url, headers=headers, verify=self.verify, cert=self.cert
 995        ) as client:
 996            yield client
 997
 998    async def _get_openid_configuration(self) -> Dict[str, Any]:
 999        if self._openid_configuration is not None:
1000            return self._openid_configuration
1001
1002        async with self._get_httpx_client() as client:
1003            request = self._get_openid_configuration_request(client)
1004            response = await client.send(request)
1005            json = response.json()
1006            self._openid_configuration = json
1007            return json
1008
1009    async def _get_jwks(self) -> jwk.JWKSet:
1010        if self._jwks is not None:
1011            return self._jwks
1012
1013        jwks_uri = self._get_endpoint_url(
1014            await self._get_openid_configuration(), "jwks_uri"
1015        )
1016        async with self._get_httpx_client() as client:
1017            response = await client.get(jwks_uri)
1018            self._jwks = jwk.JWKSet.from_json(response.text)
1019            return self._jwks
1020
1021    async def _auth_exchange_token(
1022        self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None
1023    ) -> FiefTokenResponse:
1024        token_endpoint = self._get_endpoint_url(
1025            await self._get_openid_configuration(), "token_endpoint"
1026        )
1027        async with self._get_httpx_client() as client:
1028            request = self._get_auth_exchange_token_request(
1029                client,
1030                endpoint=token_endpoint,
1031                code=code,
1032                redirect_uri=redirect_uri,
1033                code_verifier=code_verifier,
1034            )
1035            response = await client.send(request)
1036
1037            self._handle_request_error(response)
1038
1039            return response.json()

Async Fief authentication client.

FiefAsync( base_url: str, client_id: str, client_secret: Optional[str] = None, *, encryption_key: Optional[str] = None, host: Optional[str] = None, verify: Union[str, bool, ssl.SSLContext] = True, cert: Union[str, Tuple[str, Optional[str]], Tuple[str, Optional[str], Optional[str]], NoneType] = None)
713    def __init__(
714        self,
715        base_url: str,
716        client_id: str,
717        client_secret: Optional[str] = None,
718        *,
719        encryption_key: Optional[str] = None,
720        host: Optional[str] = None,
721        verify: VerifyTypes = True,
722        cert: Optional[CertTypes] = None,
723    ) -> None:
724        super().__init__(
725            base_url,
726            client_id,
727            client_secret,
728            encryption_key=encryption_key,
729            host=host,
730            verify=verify,
731            cert=cert,
732        )

Initialize the client.

Parameters
  • base_url: Base URL of your Fief tenant.
  • client_id: ID of your Fief client.
  • client_secret: Secret of your Fief client. If you're implementing a desktop app, it's not recommended to use it, since it can be easily found by the end-user in the source code. The recommended way is to use a Public client.
  • encryption_key: Encryption key of your Fief client. Necessary only if ID Token encryption is enabled.
  • **verify: Corresponds to the verify parameter of HTTPX. Useful to customize SSL connection handling.
  • **cert: Corresponds to the cert parameter of HTTPX. Useful to customize SSL connection handling.
async def auth_url( self, redirect_uri: str, *, state: Optional[str] = None, scope: Optional[List[str]] = None, code_challenge: Optional[str] = None, code_challenge_method: Optional[str] = None, lang: Optional[str] = None, extras_params: Optional[Mapping[str, str]] = None) -> str:
734    async def auth_url(
735        self,
736        redirect_uri: str,
737        *,
738        state: Optional[str] = None,
739        scope: Optional[List[str]] = None,
740        code_challenge: Optional[str] = None,
741        code_challenge_method: Optional[str] = None,
742        lang: Optional[str] = None,
743        extras_params: Optional[Mapping[str, str]] = None,
744    ) -> str:
745        """
746        Return an authorization URL.
747
748        :param redirect_uri: Your callback URI where the user will be redirected after Fief authentication.
749        :param state: Optional string that will be returned back in the callback parameters to allow you to retrieve state information.
750        :param scope: Optional list of scopes to ask for.
751        :param code_challenge: Optional code challenge for
752        [PKCE process](https://docs.fief.dev/going-further/pkce/).
753        :param code_challenge_method: Method used to hash the PKCE code challenge.
754        :param lang: Optional parameter to set the user locale.
755        Should be a valid [RFC 3066](https://www.rfc-editor.org/rfc/rfc3066) language identifier, like `fr` or `pt-PT`.
756        If not provided, the user locale is determined by their browser settings.
757        :param extras_params: Optional dictionary containing [specific parameters](https://docs.fief.dev/going-further/authorize-url/).
758
759        **Example:**
760
761        ```py
762        auth_url = await fief.auth_url("http://localhost:8000/callback", scope=["openid"])
763        ```
764        """
765        openid_configuration = await self._get_openid_configuration()
766        return self._auth_url(
767            openid_configuration,
768            redirect_uri,
769            state=state,
770            scope=scope,
771            code_challenge=code_challenge,
772            code_challenge_method=code_challenge_method,
773            lang=lang,
774            extras_params=extras_params,
775        )

Return an authorization URL.

Parameters
  • redirect_uri: Your callback URI where the user will be redirected after Fief authentication.
  • state: Optional string that will be returned back in the callback parameters to allow you to retrieve state information.
  • scope: Optional list of scopes to ask for.
  • code_challenge: Optional code challenge for PKCE process.
  • code_challenge_method: Method used to hash the PKCE code challenge.
  • lang: Optional parameter to set the user locale. Should be a valid RFC 3066 language identifier, like fr or pt-PT. If not provided, the user locale is determined by their browser settings.
  • **extras_params: Optional dictionary containing specific parameters.

Example:

auth_url = await fief.auth_url("http://localhost:8000/callback", scope=["openid"])
async def auth_callback( self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None) -> Tuple[fief_client.FiefTokenResponse, fief_client.FiefUserInfo]:
777    async def auth_callback(
778        self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None
779    ) -> Tuple[FiefTokenResponse, FiefUserInfo]:
780        """
781        Return a `FiefTokenResponse` and `FiefUserInfo` in exchange of an authorization code.
782
783        :param code: The authorization code.
784        :param redirect_uri: The exact same `redirect_uri` you passed to the authorization URL.
785        :param code_verifier:  The raw
786        [PKCE](https://docs.fief.dev/going-further/pkce/) code used to generate the code challenge during authorization.
787
788        **Example:**
789
790        ```py
791        tokens, userinfo = await fief.auth_callback("CODE", "http://localhost:8000/callback")
792        ```
793        """
794        token_response = await self._auth_exchange_token(
795            code, redirect_uri, code_verifier=code_verifier
796        )
797        jwks = await self._get_jwks()
798        userinfo = self._decode_id_token(
799            token_response["id_token"],
800            jwks,
801            code=code,
802            access_token=token_response.get("access_token"),
803        )
804        return token_response, userinfo

Return a FiefTokenResponse and FiefUserInfo in exchange of an authorization code.

Parameters
  • code: The authorization code.
  • redirect_uri: The exact same redirect_uri you passed to the authorization URL.
  • code_verifier: The raw PKCE code used to generate the code challenge during authorization.

Example:

tokens, userinfo = await fief.auth_callback("CODE", "http://localhost:8000/callback")
async def auth_refresh_token( self, refresh_token: str, *, scope: Optional[List[str]] = None) -> Tuple[fief_client.FiefTokenResponse, fief_client.FiefUserInfo]:
806    async def auth_refresh_token(
807        self, refresh_token: str, *, scope: Optional[List[str]] = None
808    ) -> Tuple[FiefTokenResponse, FiefUserInfo]:
809        """
810        Return fresh `FiefTokenResponse` and `FiefUserInfo` in exchange of a refresh token
811
812        :param refresh_token: A valid refresh token.
813        :param scope: Optional list of scopes to ask for.
814        If not provided, the access token will share the same list of scopes as requested the first time.
815        Otherwise, it should be a subset of the original list of scopes.
816
817        **Example:**
818
819        ```py
820        tokens, userinfo = await fief.auth_refresh_token("REFRESH_TOKEN")
821        ```
822        """
823        token_endpoint = self._get_endpoint_url(
824            await self._get_openid_configuration(), "token_endpoint"
825        )
826        async with self._get_httpx_client() as client:
827            request = self._get_auth_refresh_token_request(
828                client,
829                endpoint=token_endpoint,
830                refresh_token=refresh_token,
831                scope=scope,
832            )
833            response = await client.send(request)
834
835            self._handle_request_error(response)
836
837            token_response = response.json()
838
839        jwks = await self._get_jwks()
840        userinfo = self._decode_id_token(
841            token_response["id_token"],
842            jwks,
843            access_token=token_response.get("access_token"),
844        )
845        return token_response, userinfo

Return fresh FiefTokenResponse and FiefUserInfo in exchange of a refresh token

Parameters
  • refresh_token: A valid refresh token.
  • scope: Optional list of scopes to ask for. If not provided, the access token will share the same list of scopes as requested the first time. Otherwise, it should be a subset of the original list of scopes.

Example:

tokens, userinfo = await fief.auth_refresh_token("REFRESH_TOKEN")
async def validate_access_token( self, access_token: str, *, required_scope: Optional[List[str]] = None, required_permissions: Optional[List[str]] = None) -> fief_client.FiefAccessTokenInfo:
847    async def validate_access_token(
848        self,
849        access_token: str,
850        *,
851        required_scope: Optional[List[str]] = None,
852        required_permissions: Optional[List[str]] = None,
853    ) -> FiefAccessTokenInfo:
854        """
855        Check if an access token is valid and optionally that it has a required list of scopes,
856        or a required list of [permissions](https://docs.fief.dev/getting-started/access-control/).
857        Returns a `FiefAccessTokenInfo`.
858
859        :param access_token: The access token to validate.
860        :param required_scope: Optional list of scopes to check for.
861        :param required_permissions: Optional list of permissions to check for.
862
863        **Example: Validate access token with required scopes**
864
865        ```py
866        try:
867            access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_scope=["required_scope"])
868        except FiefAccessTokenInvalid:
869            print("Invalid access token")
870        except FiefAccessTokenExpired:
871            print("Expired access token")
872        except FiefAccessTokenMissingScope:
873            print("Missing required scope")
874
875        print(access_token_info)
876        ```
877
878        **Example: Validate access token with required permissions**
879
880        ```py
881        try:
882            access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_permissions=["castles:create", "castles:read"])
883        except FiefAccessTokenInvalid:
884            print("Invalid access token")
885        except FiefAccessTokenExpired:
886            print("Expired access token")
887        except FiefAccessTokenMissingPermission:
888            print("Missing required permission")
889
890        print(access_token_info)
891        ```
892        """
893        jwks = await self._get_jwks()
894        return self._validate_access_token(
895            access_token,
896            jwks,
897            required_scope=required_scope,
898            required_permissions=required_permissions,
899        )

Check if an access token is valid and optionally that it has a required list of scopes, or a required list of permissions. Returns a FiefAccessTokenInfo.

Parameters
  • access_token: The access token to validate.
  • required_scope: Optional list of scopes to check for.
  • required_permissions: Optional list of permissions to check for.

Example: Validate access token with required scopes

try:
    access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_scope=["required_scope"])
except FiefAccessTokenInvalid:
    print("Invalid access token")
except FiefAccessTokenExpired:
    print("Expired access token")
except FiefAccessTokenMissingScope:
    print("Missing required scope")

print(access_token_info)

Example: Validate access token with required permissions

try:
    access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_permissions=["castles:create", "castles:read"])
except FiefAccessTokenInvalid:
    print("Invalid access token")
except FiefAccessTokenExpired:
    print("Expired access token")
except FiefAccessTokenMissingPermission:
    print("Missing required permission")

print(access_token_info)
async def userinfo(self, access_token: str) -> fief_client.FiefUserInfo:
901    async def userinfo(self, access_token: str) -> FiefUserInfo:
902        """
903        Return fresh `FiefUserInfo` from the Fief API using a valid access token.
904
905        :param access_token: A valid access token.
906
907        **Example:**
908
909        ```py
910        userinfo = await fief.userinfo("ACCESS_TOKEN")
911        ```
912        """
913        userinfo_endpoint = self._get_endpoint_url(
914            await self._get_openid_configuration(), "userinfo_endpoint"
915        )
916        async with self._get_httpx_client() as client:
917            request = self._get_userinfo_request(
918                client, endpoint=userinfo_endpoint, access_token=access_token
919            )
920            response = await client.send(request)
921
922            self._handle_request_error(response)
923
924            return response.json()

Return fresh FiefUserInfo from the Fief API using a valid access token.

Parameters
  • access_token: A valid access token.

Example:

userinfo = await fief.userinfo("ACCESS_TOKEN")
async def update_profile( self, access_token: str, data: Dict[str, Any]) -> fief_client.FiefUserInfo:
926    async def update_profile(
927        self, access_token: str, data: Dict[str, Any]
928    ) -> FiefUserInfo:
929        """
930        Update user information with the Fief API using a valid access token.
931
932        :param access_token: A valid access token.
933        :param data: A dictionary containing the data to update.
934
935        **Example: Update email address**
936
937        ```py
938        userinfo = await fief.update_profile("ACCESS_TOKEN", { "email": "anne@nantes.city" })
939        ```
940
941        **Example: Update password**
942
943        ```py
944        userinfo = await fief.update_profile("ACCESS_TOKEN", { "password": "herminetincture" })
945        ```
946
947        **Example: Update user field**
948
949        To update [user field](https://docs.fief.dev/getting-started/user-fields/) values, you need to nest them into a `fields` dictionary, indexed by their slug.
950
951        ```py
952        userinfo = await fief.update_profile("ACCESS_TOKEN", { "fields": { "first_name": "Anne" } })
953        ```
954        """
955        update_profile_endpoint = f"{self.base_url}/api/profile"
956
957        async with self._get_httpx_client() as client:
958            request = self._get_update_profile_request(
959                client,
960                endpoint=update_profile_endpoint,
961                access_token=access_token,
962                data=data,
963            )
964            response = await client.send(request)
965
966            self._handle_request_error(response)
967
968            return response.json()

Update user information with the Fief API using a valid access token.

Parameters
  • access_token: A valid access token.
  • data: A dictionary containing the data to update.

Example: Update email address

userinfo = await fief.update_profile("ACCESS_TOKEN", { "email": "anne@nantes.city" })

Example: Update password

userinfo = await fief.update_profile("ACCESS_TOKEN", { "password": "herminetincture" })

Example: Update user field

To update user field values, you need to nest them into a fields dictionary, indexed by their slug.

userinfo = await fief.update_profile("ACCESS_TOKEN", { "fields": { "first_name": "Anne" } })
async def logout_url(self, redirect_uri: str) -> str:
970    async def logout_url(self, redirect_uri: str) -> str:
971        """
972        Returns a logout URL. If you redirect the user to this page, Fief will clear the session stored on its side.
973
974        **You're still responsible for clearing your own session mechanism if any.**
975
976        :param redirect_uri: A valid URL where the user will be redirected after the logout process:
977
978        **Example:**
979
980        ```py
981        logout_url = await fief.logout_url("http://localhost:8000")
982        ```
983        """
984        params = {"redirect_uri": redirect_uri}
985        return f"{self.base_url}/logout?{urlencode(params)}"

Returns a logout URL. If you redirect the user to this page, Fief will clear the session stored on its side.

You're still responsible for clearing your own session mechanism if any.

Parameters
  • redirect_uri: A valid URL where the user will be redirected after the logout process:

Example:

logout_url = await fief.logout_url("http://localhost:8000")
Inherited Members
fief_client.client.BaseFief
base_url
client_id
client_secret
class FiefTokenResponse(typing.TypedDict):
24class FiefTokenResponse(TypedDict):
25    """
26    Typed dictionary containing the tokens and related information returned by Fief after a successful authentication.
27    """
28
29    access_token: str
30    """Access token you can use to call the Fief API."""
31    id_token: str
32    """ID token containing user information."""
33    token_type: str
34    """Type of token, usually `bearer`."""
35    expires_in: int
36    """Number of seconds after which the tokens will expire."""
37    refresh_token: Optional[str]
38    """Token provided only if scope `offline_access` was granted. Allows you to retrieve fresh tokens using the `Fief.auth_refresh_token` method."""

Typed dictionary containing the tokens and related information returned by Fief after a successful authentication.

access_token: str

Access token you can use to call the Fief API.

id_token: str

ID token containing user information.

token_type: str

Type of token, usually bearer.

expires_in: int

Number of seconds after which the tokens will expire.

refresh_token: Optional[str]

Token provided only if scope offline_access was granted. Allows you to retrieve fresh tokens using the Fief.auth_refresh_token method.

class FiefAccessTokenInfo(typing.TypedDict):
41class FiefAccessTokenInfo(TypedDict):
42    """
43    Typed dictionary containing information about the access token.
44
45    **Example:**
46
47    ```json
48    {
49        "id": "aeeb8bfa-e8f4-4724-9427-c3d5af66190e",
50        "scope": ["openid", "required_scope"],
51        "permissions": ["castles:read", "castles:create", "castles:update", "castles:delete"],
52        "access_token": "ACCESS_TOKEN",
53    }
54    ```
55    """
56
57    id: uuid.UUID
58    """ID of the user."""
59    scope: List[str]
60    """List of granted scopes for this access token."""
61    permissions: List[str]
62    """List of [granted permissions](https://docs.fief.dev/getting-started/access-control/) for this user."""
63    access_token: str
64    """Access token you can use to call the Fief API."""

Typed dictionary containing information about the access token.

Example:

{
    "id": "aeeb8bfa-e8f4-4724-9427-c3d5af66190e",
    "scope": ["openid", "required_scope"],
    "permissions": ["castles:read", "castles:create", "castles:update", "castles:delete"],
    "access_token": "ACCESS_TOKEN",
}
id: uuid.UUID

ID of the user.

scope: List[str]

List of granted scopes for this access token.

permissions: List[str]

List of granted permissions for this user.

access_token: str

Access token you can use to call the Fief API.

class FiefUserInfo(typing.TypedDict):
 67class FiefUserInfo(TypedDict):
 68    """
 69    Dictionary containing user information.
 70
 71    **Example:**
 72
 73    ```json
 74    {
 75        "sub": "aeeb8bfa-e8f4-4724-9427-c3d5af66190e",
 76        "email": "anne@bretagne.duchy",
 77        "tenant_id": "c91ecb7f-359c-4244-8385-51ecd6c0d06b",
 78        "fields": {
 79            "first_name": "Anne",
 80            "last_name": "De Bretagne"
 81        }
 82    }
 83    ```
 84    """
 85
 86    sub: str
 87    """
 88    ID of the user.
 89    """
 90    email: str
 91    """
 92    Email address of the user.
 93    """
 94    tenant_id: str
 95    """
 96    ID of the [tenant](https://docs.fief.dev/getting-started/tenants/) associated to the user.
 97    """
 98    fields: Dict[str, Any]
 99    """
100    [User fields](https://docs.fief.dev/getting-started/user-fields/) values for this user, indexed by their slug.
101    """

Dictionary containing user information.

Example:

{
    "sub": "aeeb8bfa-e8f4-4724-9427-c3d5af66190e",
    "email": "anne@bretagne.duchy",
    "tenant_id": "c91ecb7f-359c-4244-8385-51ecd6c0d06b",
    "fields": {
        "first_name": "Anne",
        "last_name": "De Bretagne"
    }
}
sub: str

ID of the user.

email: str

Email address of the user.

tenant_id: str

ID of the tenant associated to the user.

fields: Dict[str, Any]

User fields values for this user, indexed by their slug.

class FiefError(builtins.Exception):
104class FiefError(Exception):
105    """Base Fief client error."""

Base Fief client error.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
class FiefAccessTokenExpired(fief_client.FiefError):
122class FiefAccessTokenExpired(FiefError):
123    """The access token is expired."""

The access token is expired.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
class FiefAccessTokenMissingPermission(fief_client.FiefError):
130class FiefAccessTokenMissingPermission(FiefError):
131    """The access token is missing a required permission."""

The access token is missing a required permission.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
class FiefAccessTokenMissingScope(fief_client.FiefError):
126class FiefAccessTokenMissingScope(FiefError):
127    """The access token is missing a required scope."""

The access token is missing a required scope.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
class FiefAccessTokenInvalid(fief_client.FiefError):
118class FiefAccessTokenInvalid(FiefError):
119    """The access token is invalid."""

The access token is invalid.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
class FiefIdTokenInvalid(fief_client.FiefError):
134class FiefIdTokenInvalid(FiefError):
135    """The ID token is invalid."""

The ID token is invalid.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
class FiefRequestError(fief_client.FiefError):
108class FiefRequestError(FiefError):
109    """The request to Fief server resulted in an error."""
110
111    def __init__(self, status_code: int, detail: str) -> None:
112        self.status_code = status_code
113        self.detail = detail
114        self.message = f"[{status_code}] - {detail}"
115        super().__init__(self.message)

The request to Fief server resulted in an error.

FiefRequestError(status_code: int, detail: str)
111    def __init__(self, status_code: int, detail: str) -> None:
112        self.status_code = status_code
113        self.detail = detail
114        self.message = f"[{status_code}] - {detail}"
115        super().__init__(self.message)
Inherited Members
builtins.BaseException
with_traceback