fief_client
Fief client for Python.
1"Fief client for Python." 2from fief_client.client import ( 3 Fief, 4 FiefAccessTokenACRTooLow, 5 FiefAccessTokenExpired, 6 FiefAccessTokenInfo, 7 FiefAccessTokenInvalid, 8 FiefAccessTokenMissingPermission, 9 FiefAccessTokenMissingScope, 10 FiefACR, 11 FiefAsync, 12 FiefError, 13 FiefIdTokenInvalid, 14 FiefRequestError, 15 FiefTokenResponse, 16 FiefUserInfo, 17) 18 19__version__ = "0.18.6" 20 21__all__ = [ 22 "Fief", 23 "FiefACR", 24 "FiefAsync", 25 "FiefTokenResponse", 26 "FiefAccessTokenInfo", 27 "FiefUserInfo", 28 "FiefError", 29 "FiefAccessTokenACRTooLow", 30 "FiefAccessTokenExpired", 31 "FiefAccessTokenMissingPermission", 32 "FiefAccessTokenMissingScope", 33 "FiefAccessTokenInvalid", 34 "FiefIdTokenInvalid", 35 "FiefRequestError", 36 "crypto", 37 "pkce", 38 "integrations", 39]
496class Fief(BaseFief): 497 """Sync Fief authentication client.""" 498 499 def __init__( 500 self, 501 base_url: str, 502 client_id: str, 503 client_secret: Optional[str] = None, 504 *, 505 encryption_key: Optional[str] = None, 506 host: Optional[str] = None, 507 verify: VerifyTypes = True, 508 cert: Optional[CertTypes] = None, 509 ) -> None: 510 super().__init__( 511 base_url, 512 client_id, 513 client_secret, 514 encryption_key=encryption_key, 515 host=host, 516 verify=verify, 517 cert=cert, 518 ) 519 520 def auth_url( 521 self, 522 redirect_uri: str, 523 *, 524 state: Optional[str] = None, 525 scope: Optional[List[str]] = None, 526 code_challenge: Optional[str] = None, 527 code_challenge_method: Optional[str] = None, 528 lang: Optional[str] = None, 529 extras_params: Optional[Mapping[str, str]] = None, 530 ) -> str: 531 """ 532 Return an authorization URL. 533 534 :param redirect_uri: Your callback URI where the user will be redirected after Fief authentication. 535 :param state: Optional string that will be returned back in the callback parameters to allow you to retrieve state information. 536 :param scope: Optional list of scopes to ask for. 537 :param code_challenge: Optional code challenge for 538 [PKCE process](https://docs.fief.dev/going-further/pkce/). 539 :param code_challenge_method: Method used to hash the PKCE code challenge. 540 :param lang: Optional parameter to set the user locale. 541 Should be a valid [RFC 3066](https://www.rfc-editor.org/rfc/rfc3066) language identifier, like `fr` or `pt-PT`. 542 If not provided, the user locale is determined by their browser settings. 543 :param extras_params: Optional dictionary containing [specific parameters](https://docs.fief.dev/going-further/authorize-url/). 544 545 **Example:** 546 547 ```py 548 auth_url = fief.auth_url("http://localhost:8000/callback", scope=["openid"]) 549 ``` 550 """ 551 openid_configuration = self._get_openid_configuration() 552 return self._auth_url( 553 openid_configuration, 554 redirect_uri, 555 state=state, 556 scope=scope, 557 code_challenge=code_challenge, 558 code_challenge_method=code_challenge_method, 559 lang=lang, 560 extras_params=extras_params, 561 ) 562 563 def auth_callback( 564 self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None 565 ) -> Tuple[FiefTokenResponse, FiefUserInfo]: 566 """ 567 Return a `FiefTokenResponse` and `FiefUserInfo` in exchange of an authorization code. 568 569 :param code: The authorization code. 570 :param redirect_uri: The exact same `redirect_uri` you passed to the authorization URL. 571 :param code_verifier: The raw 572 [PKCE](https://docs.fief.dev/going-further/pkce/) code used to generate the code challenge during authorization. 573 574 **Example:** 575 576 ```py 577 tokens, userinfo = fief.auth_callback("CODE", "http://localhost:8000/callback") 578 ``` 579 """ 580 token_response = self._auth_exchange_token( 581 code, redirect_uri, code_verifier=code_verifier 582 ) 583 jwks = self._get_jwks() 584 userinfo = self._decode_id_token( 585 token_response["id_token"], 586 jwks, 587 code=code, 588 access_token=token_response.get("access_token"), 589 ) 590 return token_response, userinfo 591 592 def auth_refresh_token( 593 self, refresh_token: str, *, scope: Optional[List[str]] = None 594 ) -> Tuple[FiefTokenResponse, FiefUserInfo]: 595 """ 596 Return fresh `FiefTokenResponse` and `FiefUserInfo` in exchange of a refresh token 597 598 :param refresh_token: A valid refresh token. 599 :param scope: Optional list of scopes to ask for. 600 If not provided, the access token will share the same list of scopes as requested the first time. 601 Otherwise, it should be a subset of the original list of scopes. 602 603 **Example:** 604 605 ```py 606 tokens, userinfo = fief.auth_refresh_token("REFRESH_TOKEN") 607 ``` 608 """ 609 token_endpoint = self._get_endpoint_url( 610 self._get_openid_configuration(), "token_endpoint" 611 ) 612 with self._get_httpx_client() as client: 613 request = self._get_auth_refresh_token_request( 614 client, 615 endpoint=token_endpoint, 616 refresh_token=refresh_token, 617 scope=scope, 618 ) 619 response = client.send(request) 620 621 self._handle_request_error(response) 622 623 token_response = response.json() 624 jwks = self._get_jwks() 625 userinfo = self._decode_id_token( 626 token_response["id_token"], 627 jwks, 628 access_token=token_response.get("access_token"), 629 ) 630 return token_response, userinfo 631 632 def validate_access_token( 633 self, 634 access_token: str, 635 *, 636 required_scope: Optional[List[str]] = None, 637 required_acr: Optional[FiefACR] = None, 638 required_permissions: Optional[List[str]] = None, 639 ) -> FiefAccessTokenInfo: 640 """ 641 Check if an access token is valid and optionally that it has a required list of scopes, 642 or a required list of [permissions](https://docs.fief.dev/getting-started/access-control/). 643 Returns a `FiefAccessTokenInfo`. 644 645 :param access_token: The access token to validate. 646 :param required_scope: Optional list of scopes to check for. 647 :param required_acr: Optional minimum ACR level required. 648 Read more: https://docs.fief.dev/going-further/acr/ 649 :param required_permissions: Optional list of permissions to check for. 650 651 **Example: Validate access token with required scopes** 652 653 ```py 654 try: 655 access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_scope=["required_scope"]) 656 except FiefAccessTokenInvalid: 657 print("Invalid access token") 658 except FiefAccessTokenExpired: 659 print("Expired access token") 660 except FiefAccessTokenMissingScope: 661 print("Missing required scope") 662 663 print(access_token_info) 664 ``` 665 666 **Example: Validate access token with minimum ACR level** 667 668 ```py 669 try: 670 access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_acr=FiefACR.LEVEL_ONE) 671 except FiefAccessTokenInvalid: 672 print("Invalid access token") 673 except FiefAccessTokenExpired: 674 print("Expired access token") 675 except FiefAccessTokenACRTooLow: 676 print("ACR too low") 677 678 print(access_token_info) 679 ``` 680 681 **Example: Validate access token with required permissions** 682 683 ```py 684 try: 685 access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_permissions=["castles:create", "castles:read"]) 686 except FiefAccessTokenInvalid: 687 print("Invalid access token") 688 except FiefAccessTokenExpired: 689 print("Expired access token") 690 except FiefAccessTokenMissingPermission: 691 print("Missing required permission") 692 693 print(access_token_info) 694 ``` 695 """ 696 jwks = self._get_jwks() 697 return self._validate_access_token( 698 access_token, 699 jwks, 700 required_scope=required_scope, 701 required_acr=required_acr, 702 required_permissions=required_permissions, 703 ) 704 705 def userinfo(self, access_token: str) -> FiefUserInfo: 706 """ 707 Return fresh `FiefUserInfo` from the Fief API using a valid access token. 708 709 :param access_token: A valid access token. 710 711 **Example:** 712 713 ```py 714 userinfo = fief.userinfo("ACCESS_TOKEN") 715 ``` 716 """ 717 userinfo_endpoint = self._get_endpoint_url( 718 self._get_openid_configuration(), "userinfo_endpoint" 719 ) 720 with self._get_httpx_client() as client: 721 request = self._get_userinfo_request( 722 client, endpoint=userinfo_endpoint, access_token=access_token 723 ) 724 response = client.send(request) 725 726 self._handle_request_error(response) 727 728 return response.json() 729 730 def update_profile(self, access_token: str, data: Dict[str, Any]) -> FiefUserInfo: 731 """ 732 Update user information with the Fief API using a valid access token. 733 734 :param access_token: A valid access token. 735 :param data: A dictionary containing the data to update. 736 737 **Example: Update user field** 738 739 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. 740 741 ```py 742 userinfo = fief.update_profile("ACCESS_TOKEN", { "fields": { "first_name": "Anne" } }) 743 ``` 744 """ 745 update_profile_endpoint = f"{self.base_url}/api/profile" 746 747 with self._get_httpx_client() as client: 748 request = self._get_update_profile_request( 749 client, 750 endpoint=update_profile_endpoint, 751 access_token=access_token, 752 data=data, 753 ) 754 response = client.send(request) 755 756 self._handle_request_error(response) 757 758 return response.json() 759 760 def change_password(self, access_token: str, new_password: str) -> FiefUserInfo: 761 """ 762 Change the user password with the Fief API using a valid access token. 763 764 **An access token with an ACR of at least level 1 is required.** 765 766 :param access_token: A valid access token. 767 :param new_password: The new password. 768 769 **Example** 770 771 ```py 772 userinfo = fief.change_password("ACCESS_TOKEN", "herminetincture") 773 ``` 774 """ 775 change_password_profile_endpoint = f"{self.base_url}/api/password" 776 777 with self._get_httpx_client() as client: 778 request = self._get_change_password_request( 779 client, 780 endpoint=change_password_profile_endpoint, 781 access_token=access_token, 782 new_password=new_password, 783 ) 784 response = client.send(request) 785 786 self._handle_request_error(response) 787 788 return response.json() 789 790 def email_change(self, access_token: str, email: str) -> FiefUserInfo: 791 """ 792 Request an email change with the Fief API using a valid access token. 793 794 The user will receive a verification code on this new email address. 795 It shall be used with the method `email_verify` to complete the modification. 796 797 **An access token with an ACR of at least level 1 is required.** 798 799 :param access_token: A valid access token. 800 :param email: The new email address. 801 802 **Example** 803 804 ```py 805 userinfo = fief.email_change("ACCESS_TOKEN", "anne@nantes.city") 806 ``` 807 """ 808 email_change_endpoint = f"{self.base_url}/api/email/change" 809 810 with self._get_httpx_client() as client: 811 request = self._get_email_change_request( 812 client, 813 endpoint=email_change_endpoint, 814 access_token=access_token, 815 email=email, 816 ) 817 response = client.send(request) 818 819 self._handle_request_error(response) 820 821 return response.json() 822 823 def email_verify(self, access_token: str, code: str) -> FiefUserInfo: 824 """ 825 Verify the user email with the Fief API using a valid access token and verification code. 826 827 **An access token with an ACR of at least level 1 is required.** 828 829 :param access_token: A valid access token. 830 :param code: The verification code received by email. 831 832 **Example** 833 834 ```py 835 userinfo = fief.email_verify("ACCESS_TOKEN", "ABCDE") 836 ``` 837 """ 838 email_verify_endpoint = f"{self.base_url}/api/email/verify" 839 840 with self._get_httpx_client() as client: 841 request = self._get_email_verify_request( 842 client, 843 endpoint=email_verify_endpoint, 844 access_token=access_token, 845 code=code, 846 ) 847 response = client.send(request) 848 849 self._handle_request_error(response) 850 851 return response.json() 852 853 def logout_url(self, redirect_uri: str) -> str: 854 """ 855 Returns a logout URL. If you redirect the user to this page, Fief will clear the session stored on its side. 856 857 **You're still responsible for clearing your own session mechanism if any.** 858 859 :param redirect_uri: A valid URL where the user will be redirected after the logout process. 860 861 **Example:** 862 863 ```py 864 logout_url = fief.logout_url("http://localhost:8000") 865 ``` 866 """ 867 params = {"redirect_uri": redirect_uri} 868 return f"{self.base_url}/logout?{urlencode(params)}" 869 870 @contextlib.contextmanager 871 def _get_httpx_client(self): 872 headers = {} 873 if self.host is not None: 874 headers["Host"] = self.host 875 876 with httpx.Client( 877 base_url=self.base_url, headers=headers, verify=self.verify, cert=self.cert 878 ) as client: 879 yield client 880 881 def _get_openid_configuration(self) -> Dict[str, Any]: 882 if self._openid_configuration is not None: 883 return self._openid_configuration 884 885 with self._get_httpx_client() as client: 886 request = self._get_openid_configuration_request(client) 887 response = client.send(request) 888 json = response.json() 889 self._openid_configuration = json 890 return json 891 892 def _get_jwks(self) -> jwk.JWKSet: 893 if self._jwks is not None: 894 return self._jwks 895 896 jwks_uri = self._get_endpoint_url(self._get_openid_configuration(), "jwks_uri") 897 with self._get_httpx_client() as client: 898 response = client.get(jwks_uri) 899 self._jwks = jwk.JWKSet.from_json(response.text) 900 return self._jwks 901 902 def _auth_exchange_token( 903 self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None 904 ) -> FiefTokenResponse: 905 token_endpoint = self._get_endpoint_url( 906 self._get_openid_configuration(), "token_endpoint" 907 ) 908 with self._get_httpx_client() as client: 909 request = self._get_auth_exchange_token_request( 910 client, 911 endpoint=token_endpoint, 912 code=code, 913 redirect_uri=redirect_uri, 914 code_verifier=code_verifier, 915 ) 916 response = client.send(request) 917 918 self._handle_request_error(response) 919 920 return response.json()
Sync Fief authentication client.
499 def __init__( 500 self, 501 base_url: str, 502 client_id: str, 503 client_secret: Optional[str] = None, 504 *, 505 encryption_key: Optional[str] = None, 506 host: Optional[str] = None, 507 verify: VerifyTypes = True, 508 cert: Optional[CertTypes] = None, 509 ) -> None: 510 super().__init__( 511 base_url, 512 client_id, 513 client_secret, 514 encryption_key=encryption_key, 515 host=host, 516 verify=verify, 517 cert=cert, 518 )
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.
520 def auth_url( 521 self, 522 redirect_uri: str, 523 *, 524 state: Optional[str] = None, 525 scope: Optional[List[str]] = None, 526 code_challenge: Optional[str] = None, 527 code_challenge_method: Optional[str] = None, 528 lang: Optional[str] = None, 529 extras_params: Optional[Mapping[str, str]] = None, 530 ) -> str: 531 """ 532 Return an authorization URL. 533 534 :param redirect_uri: Your callback URI where the user will be redirected after Fief authentication. 535 :param state: Optional string that will be returned back in the callback parameters to allow you to retrieve state information. 536 :param scope: Optional list of scopes to ask for. 537 :param code_challenge: Optional code challenge for 538 [PKCE process](https://docs.fief.dev/going-further/pkce/). 539 :param code_challenge_method: Method used to hash the PKCE code challenge. 540 :param lang: Optional parameter to set the user locale. 541 Should be a valid [RFC 3066](https://www.rfc-editor.org/rfc/rfc3066) language identifier, like `fr` or `pt-PT`. 542 If not provided, the user locale is determined by their browser settings. 543 :param extras_params: Optional dictionary containing [specific parameters](https://docs.fief.dev/going-further/authorize-url/). 544 545 **Example:** 546 547 ```py 548 auth_url = fief.auth_url("http://localhost:8000/callback", scope=["openid"]) 549 ``` 550 """ 551 openid_configuration = self._get_openid_configuration() 552 return self._auth_url( 553 openid_configuration, 554 redirect_uri, 555 state=state, 556 scope=scope, 557 code_challenge=code_challenge, 558 code_challenge_method=code_challenge_method, 559 lang=lang, 560 extras_params=extras_params, 561 )
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
orpt-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"])
563 def auth_callback( 564 self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None 565 ) -> Tuple[FiefTokenResponse, FiefUserInfo]: 566 """ 567 Return a `FiefTokenResponse` and `FiefUserInfo` in exchange of an authorization code. 568 569 :param code: The authorization code. 570 :param redirect_uri: The exact same `redirect_uri` you passed to the authorization URL. 571 :param code_verifier: The raw 572 [PKCE](https://docs.fief.dev/going-further/pkce/) code used to generate the code challenge during authorization. 573 574 **Example:** 575 576 ```py 577 tokens, userinfo = fief.auth_callback("CODE", "http://localhost:8000/callback") 578 ``` 579 """ 580 token_response = self._auth_exchange_token( 581 code, redirect_uri, code_verifier=code_verifier 582 ) 583 jwks = self._get_jwks() 584 userinfo = self._decode_id_token( 585 token_response["id_token"], 586 jwks, 587 code=code, 588 access_token=token_response.get("access_token"), 589 ) 590 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")
592 def auth_refresh_token( 593 self, refresh_token: str, *, scope: Optional[List[str]] = None 594 ) -> Tuple[FiefTokenResponse, FiefUserInfo]: 595 """ 596 Return fresh `FiefTokenResponse` and `FiefUserInfo` in exchange of a refresh token 597 598 :param refresh_token: A valid refresh token. 599 :param scope: Optional list of scopes to ask for. 600 If not provided, the access token will share the same list of scopes as requested the first time. 601 Otherwise, it should be a subset of the original list of scopes. 602 603 **Example:** 604 605 ```py 606 tokens, userinfo = fief.auth_refresh_token("REFRESH_TOKEN") 607 ``` 608 """ 609 token_endpoint = self._get_endpoint_url( 610 self._get_openid_configuration(), "token_endpoint" 611 ) 612 with self._get_httpx_client() as client: 613 request = self._get_auth_refresh_token_request( 614 client, 615 endpoint=token_endpoint, 616 refresh_token=refresh_token, 617 scope=scope, 618 ) 619 response = client.send(request) 620 621 self._handle_request_error(response) 622 623 token_response = response.json() 624 jwks = self._get_jwks() 625 userinfo = self._decode_id_token( 626 token_response["id_token"], 627 jwks, 628 access_token=token_response.get("access_token"), 629 ) 630 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")
632 def validate_access_token( 633 self, 634 access_token: str, 635 *, 636 required_scope: Optional[List[str]] = None, 637 required_acr: Optional[FiefACR] = None, 638 required_permissions: Optional[List[str]] = None, 639 ) -> FiefAccessTokenInfo: 640 """ 641 Check if an access token is valid and optionally that it has a required list of scopes, 642 or a required list of [permissions](https://docs.fief.dev/getting-started/access-control/). 643 Returns a `FiefAccessTokenInfo`. 644 645 :param access_token: The access token to validate. 646 :param required_scope: Optional list of scopes to check for. 647 :param required_acr: Optional minimum ACR level required. 648 Read more: https://docs.fief.dev/going-further/acr/ 649 :param required_permissions: Optional list of permissions to check for. 650 651 **Example: Validate access token with required scopes** 652 653 ```py 654 try: 655 access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_scope=["required_scope"]) 656 except FiefAccessTokenInvalid: 657 print("Invalid access token") 658 except FiefAccessTokenExpired: 659 print("Expired access token") 660 except FiefAccessTokenMissingScope: 661 print("Missing required scope") 662 663 print(access_token_info) 664 ``` 665 666 **Example: Validate access token with minimum ACR level** 667 668 ```py 669 try: 670 access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_acr=FiefACR.LEVEL_ONE) 671 except FiefAccessTokenInvalid: 672 print("Invalid access token") 673 except FiefAccessTokenExpired: 674 print("Expired access token") 675 except FiefAccessTokenACRTooLow: 676 print("ACR too low") 677 678 print(access_token_info) 679 ``` 680 681 **Example: Validate access token with required permissions** 682 683 ```py 684 try: 685 access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_permissions=["castles:create", "castles:read"]) 686 except FiefAccessTokenInvalid: 687 print("Invalid access token") 688 except FiefAccessTokenExpired: 689 print("Expired access token") 690 except FiefAccessTokenMissingPermission: 691 print("Missing required permission") 692 693 print(access_token_info) 694 ``` 695 """ 696 jwks = self._get_jwks() 697 return self._validate_access_token( 698 access_token, 699 jwks, 700 required_scope=required_scope, 701 required_acr=required_acr, 702 required_permissions=required_permissions, 703 )
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_acr: Optional minimum ACR level required. Read more: https://docs.fief.dev/going-further/acr/
- 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 minimum ACR level
try:
access_token_info = fief.validate_access_token("ACCESS_TOKEN", required_acr=FiefACR.LEVEL_ONE)
except FiefAccessTokenInvalid:
print("Invalid access token")
except FiefAccessTokenExpired:
print("Expired access token")
except FiefAccessTokenACRTooLow:
print("ACR too low")
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)
705 def userinfo(self, access_token: str) -> FiefUserInfo: 706 """ 707 Return fresh `FiefUserInfo` from the Fief API using a valid access token. 708 709 :param access_token: A valid access token. 710 711 **Example:** 712 713 ```py 714 userinfo = fief.userinfo("ACCESS_TOKEN") 715 ``` 716 """ 717 userinfo_endpoint = self._get_endpoint_url( 718 self._get_openid_configuration(), "userinfo_endpoint" 719 ) 720 with self._get_httpx_client() as client: 721 request = self._get_userinfo_request( 722 client, endpoint=userinfo_endpoint, access_token=access_token 723 ) 724 response = client.send(request) 725 726 self._handle_request_error(response) 727 728 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")
730 def update_profile(self, access_token: str, data: Dict[str, Any]) -> FiefUserInfo: 731 """ 732 Update user information with the Fief API using a valid access token. 733 734 :param access_token: A valid access token. 735 :param data: A dictionary containing the data to update. 736 737 **Example: Update user field** 738 739 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. 740 741 ```py 742 userinfo = fief.update_profile("ACCESS_TOKEN", { "fields": { "first_name": "Anne" } }) 743 ``` 744 """ 745 update_profile_endpoint = f"{self.base_url}/api/profile" 746 747 with self._get_httpx_client() as client: 748 request = self._get_update_profile_request( 749 client, 750 endpoint=update_profile_endpoint, 751 access_token=access_token, 752 data=data, 753 ) 754 response = client.send(request) 755 756 self._handle_request_error(response) 757 758 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 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" } })
760 def change_password(self, access_token: str, new_password: str) -> FiefUserInfo: 761 """ 762 Change the user password with the Fief API using a valid access token. 763 764 **An access token with an ACR of at least level 1 is required.** 765 766 :param access_token: A valid access token. 767 :param new_password: The new password. 768 769 **Example** 770 771 ```py 772 userinfo = fief.change_password("ACCESS_TOKEN", "herminetincture") 773 ``` 774 """ 775 change_password_profile_endpoint = f"{self.base_url}/api/password" 776 777 with self._get_httpx_client() as client: 778 request = self._get_change_password_request( 779 client, 780 endpoint=change_password_profile_endpoint, 781 access_token=access_token, 782 new_password=new_password, 783 ) 784 response = client.send(request) 785 786 self._handle_request_error(response) 787 788 return response.json()
Change the user password with the Fief API using a valid access token.
An access token with an ACR of at least level 1 is required.
Parameters
- access_token: A valid access token.
- new_password: The new password.
Example
userinfo = fief.change_password("ACCESS_TOKEN", "herminetincture")
790 def email_change(self, access_token: str, email: str) -> FiefUserInfo: 791 """ 792 Request an email change with the Fief API using a valid access token. 793 794 The user will receive a verification code on this new email address. 795 It shall be used with the method `email_verify` to complete the modification. 796 797 **An access token with an ACR of at least level 1 is required.** 798 799 :param access_token: A valid access token. 800 :param email: The new email address. 801 802 **Example** 803 804 ```py 805 userinfo = fief.email_change("ACCESS_TOKEN", "anne@nantes.city") 806 ``` 807 """ 808 email_change_endpoint = f"{self.base_url}/api/email/change" 809 810 with self._get_httpx_client() as client: 811 request = self._get_email_change_request( 812 client, 813 endpoint=email_change_endpoint, 814 access_token=access_token, 815 email=email, 816 ) 817 response = client.send(request) 818 819 self._handle_request_error(response) 820 821 return response.json()
Request an email change with the Fief API using a valid access token.
The user will receive a verification code on this new email address.
It shall be used with the method email_verify
to complete the modification.
An access token with an ACR of at least level 1 is required.
Parameters
- access_token: A valid access token.
- email: The new email address.
Example
userinfo = fief.email_change("ACCESS_TOKEN", "anne@nantes.city")
823 def email_verify(self, access_token: str, code: str) -> FiefUserInfo: 824 """ 825 Verify the user email with the Fief API using a valid access token and verification code. 826 827 **An access token with an ACR of at least level 1 is required.** 828 829 :param access_token: A valid access token. 830 :param code: The verification code received by email. 831 832 **Example** 833 834 ```py 835 userinfo = fief.email_verify("ACCESS_TOKEN", "ABCDE") 836 ``` 837 """ 838 email_verify_endpoint = f"{self.base_url}/api/email/verify" 839 840 with self._get_httpx_client() as client: 841 request = self._get_email_verify_request( 842 client, 843 endpoint=email_verify_endpoint, 844 access_token=access_token, 845 code=code, 846 ) 847 response = client.send(request) 848 849 self._handle_request_error(response) 850 851 return response.json()
Verify the user email with the Fief API using a valid access token and verification code.
An access token with an ACR of at least level 1 is required.
Parameters
- access_token: A valid access token.
- code: The verification code received by email.
Example
userinfo = fief.email_verify("ACCESS_TOKEN", "ABCDE")
853 def logout_url(self, redirect_uri: str) -> str: 854 """ 855 Returns a logout URL. If you redirect the user to this page, Fief will clear the session stored on its side. 856 857 **You're still responsible for clearing your own session mechanism if any.** 858 859 :param redirect_uri: A valid URL where the user will be redirected after the logout process. 860 861 **Example:** 862 863 ```py 864 logout_url = fief.logout_url("http://localhost:8000") 865 ``` 866 """ 867 params = {"redirect_uri": redirect_uri} 868 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
- encryption_key
- host
- verify
- cert
18class FiefACR(str, Enum): 19 """ 20 List of defined Authentication Context Class Reference. 21 """ 22 23 LEVEL_ZERO = "0" 24 """Level 0. No authentication was performed, a previous session was used.""" 25 LEVEL_ONE = "1" 26 """Level 1. Password authentication was performed.""" 27 28 def __lt__(self, other: object) -> bool: 29 return self._compare(other, True, True) 30 31 def __le__(self, other: object) -> bool: 32 return self._compare(other, False, True) 33 34 def __gt__(self, other: object) -> bool: 35 return self._compare(other, True, False) 36 37 def __ge__(self, other: object) -> bool: 38 return self._compare(other, False, False) 39 40 def _compare(self, other: object, strict: bool, asc: bool) -> bool: 41 if not isinstance(other, FiefACR): 42 return NotImplemented # pragma: no cover 43 44 if self == other: 45 return not strict 46 47 for elem in FiefACR: 48 if self == elem: 49 return asc 50 elif other == elem: 51 return not asc 52 raise RuntimeError() # pragma: no cover
List of defined Authentication Context Class Reference.
Level 0. No authentication was performed, a previous session was used.
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
923class FiefAsync(BaseFief): 924 """Async Fief authentication client.""" 925 926 def __init__( 927 self, 928 base_url: str, 929 client_id: str, 930 client_secret: Optional[str] = None, 931 *, 932 encryption_key: Optional[str] = None, 933 host: Optional[str] = None, 934 verify: VerifyTypes = True, 935 cert: Optional[CertTypes] = None, 936 ) -> None: 937 super().__init__( 938 base_url, 939 client_id, 940 client_secret, 941 encryption_key=encryption_key, 942 host=host, 943 verify=verify, 944 cert=cert, 945 ) 946 947 async def auth_url( 948 self, 949 redirect_uri: str, 950 *, 951 state: Optional[str] = None, 952 scope: Optional[List[str]] = None, 953 code_challenge: Optional[str] = None, 954 code_challenge_method: Optional[str] = None, 955 lang: Optional[str] = None, 956 extras_params: Optional[Mapping[str, str]] = None, 957 ) -> str: 958 """ 959 Return an authorization URL. 960 961 :param redirect_uri: Your callback URI where the user will be redirected after Fief authentication. 962 :param state: Optional string that will be returned back in the callback parameters to allow you to retrieve state information. 963 :param scope: Optional list of scopes to ask for. 964 :param code_challenge: Optional code challenge for 965 [PKCE process](https://docs.fief.dev/going-further/pkce/). 966 :param code_challenge_method: Method used to hash the PKCE code challenge. 967 :param lang: Optional parameter to set the user locale. 968 Should be a valid [RFC 3066](https://www.rfc-editor.org/rfc/rfc3066) language identifier, like `fr` or `pt-PT`. 969 If not provided, the user locale is determined by their browser settings. 970 :param extras_params: Optional dictionary containing [specific parameters](https://docs.fief.dev/going-further/authorize-url/). 971 972 **Example:** 973 974 ```py 975 auth_url = await fief.auth_url("http://localhost:8000/callback", scope=["openid"]) 976 ``` 977 """ 978 openid_configuration = await self._get_openid_configuration() 979 return self._auth_url( 980 openid_configuration, 981 redirect_uri, 982 state=state, 983 scope=scope, 984 code_challenge=code_challenge, 985 code_challenge_method=code_challenge_method, 986 lang=lang, 987 extras_params=extras_params, 988 ) 989 990 async def auth_callback( 991 self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None 992 ) -> Tuple[FiefTokenResponse, FiefUserInfo]: 993 """ 994 Return a `FiefTokenResponse` and `FiefUserInfo` in exchange of an authorization code. 995 996 :param code: The authorization code. 997 :param redirect_uri: The exact same `redirect_uri` you passed to the authorization URL. 998 :param code_verifier: The raw 999 [PKCE](https://docs.fief.dev/going-further/pkce/) code used to generate the code challenge during authorization. 1000 1001 **Example:** 1002 1003 ```py 1004 tokens, userinfo = await fief.auth_callback("CODE", "http://localhost:8000/callback") 1005 ``` 1006 """ 1007 token_response = await self._auth_exchange_token( 1008 code, redirect_uri, code_verifier=code_verifier 1009 ) 1010 jwks = await self._get_jwks() 1011 userinfo = self._decode_id_token( 1012 token_response["id_token"], 1013 jwks, 1014 code=code, 1015 access_token=token_response.get("access_token"), 1016 ) 1017 return token_response, userinfo 1018 1019 async def auth_refresh_token( 1020 self, refresh_token: str, *, scope: Optional[List[str]] = None 1021 ) -> Tuple[FiefTokenResponse, FiefUserInfo]: 1022 """ 1023 Return fresh `FiefTokenResponse` and `FiefUserInfo` in exchange of a refresh token 1024 1025 :param refresh_token: A valid refresh token. 1026 :param scope: Optional list of scopes to ask for. 1027 If not provided, the access token will share the same list of scopes as requested the first time. 1028 Otherwise, it should be a subset of the original list of scopes. 1029 1030 **Example:** 1031 1032 ```py 1033 tokens, userinfo = await fief.auth_refresh_token("REFRESH_TOKEN") 1034 ``` 1035 """ 1036 token_endpoint = self._get_endpoint_url( 1037 await self._get_openid_configuration(), "token_endpoint" 1038 ) 1039 async with self._get_httpx_client() as client: 1040 request = self._get_auth_refresh_token_request( 1041 client, 1042 endpoint=token_endpoint, 1043 refresh_token=refresh_token, 1044 scope=scope, 1045 ) 1046 response = await client.send(request) 1047 1048 self._handle_request_error(response) 1049 1050 token_response = response.json() 1051 1052 jwks = await self._get_jwks() 1053 userinfo = self._decode_id_token( 1054 token_response["id_token"], 1055 jwks, 1056 access_token=token_response.get("access_token"), 1057 ) 1058 return token_response, userinfo 1059 1060 async def validate_access_token( 1061 self, 1062 access_token: str, 1063 *, 1064 required_scope: Optional[List[str]] = None, 1065 required_acr: Optional[FiefACR] = None, 1066 required_permissions: Optional[List[str]] = None, 1067 ) -> FiefAccessTokenInfo: 1068 """ 1069 Check if an access token is valid and optionally that it has a required list of scopes, 1070 or a required list of [permissions](https://docs.fief.dev/getting-started/access-control/). 1071 Returns a `FiefAccessTokenInfo`. 1072 1073 :param access_token: The access token to validate. 1074 :param required_scope: Optional list of scopes to check for. 1075 :param required_acr: Optional minimum ACR level required. 1076 Read more: https://docs.fief.dev/going-further/acr/ 1077 :param required_permissions: Optional list of permissions to check for. 1078 1079 **Example: Validate access token with required scopes** 1080 1081 ```py 1082 try: 1083 access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_scope=["required_scope"]) 1084 except FiefAccessTokenInvalid: 1085 print("Invalid access token") 1086 except FiefAccessTokenExpired: 1087 print("Expired access token") 1088 except FiefAccessTokenMissingScope: 1089 print("Missing required scope") 1090 1091 print(access_token_info) 1092 ``` 1093 1094 **Example: Validate access token with minimum ACR level** 1095 1096 ```py 1097 try: 1098 access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_acr=FiefACR.LEVEL_ONE) 1099 except FiefAccessTokenInvalid: 1100 print("Invalid access token") 1101 except FiefAccessTokenExpired: 1102 print("Expired access token") 1103 except FiefAccessTokenACRTooLow: 1104 print("ACR too low") 1105 1106 print(access_token_info) 1107 ``` 1108 1109 **Example: Validate access token with required permissions** 1110 1111 ```py 1112 try: 1113 access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_permissions=["castles:create", "castles:read"]) 1114 except FiefAccessTokenInvalid: 1115 print("Invalid access token") 1116 except FiefAccessTokenExpired: 1117 print("Expired access token") 1118 except FiefAccessTokenMissingPermission: 1119 print("Missing required permission") 1120 1121 print(access_token_info) 1122 ``` 1123 """ 1124 jwks = await self._get_jwks() 1125 return self._validate_access_token( 1126 access_token, 1127 jwks, 1128 required_scope=required_scope, 1129 required_acr=required_acr, 1130 required_permissions=required_permissions, 1131 ) 1132 1133 async def userinfo(self, access_token: str) -> FiefUserInfo: 1134 """ 1135 Return fresh `FiefUserInfo` from the Fief API using a valid access token. 1136 1137 :param access_token: A valid access token. 1138 1139 **Example:** 1140 1141 ```py 1142 userinfo = await fief.userinfo("ACCESS_TOKEN") 1143 ``` 1144 """ 1145 userinfo_endpoint = self._get_endpoint_url( 1146 await self._get_openid_configuration(), "userinfo_endpoint" 1147 ) 1148 async with self._get_httpx_client() as client: 1149 request = self._get_userinfo_request( 1150 client, endpoint=userinfo_endpoint, access_token=access_token 1151 ) 1152 response = await client.send(request) 1153 1154 self._handle_request_error(response) 1155 1156 return response.json() 1157 1158 async def update_profile( 1159 self, access_token: str, data: Dict[str, Any] 1160 ) -> FiefUserInfo: 1161 """ 1162 Update user information with the Fief API using a valid access token. 1163 1164 :param access_token: A valid access token. 1165 :param data: A dictionary containing the data to update. 1166 1167 **Example: Update user field** 1168 1169 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. 1170 1171 ```py 1172 userinfo = await fief.update_profile("ACCESS_TOKEN", { "fields": { "first_name": "Anne" } }) 1173 ``` 1174 """ 1175 update_profile_endpoint = f"{self.base_url}/api/profile" 1176 1177 async with self._get_httpx_client() as client: 1178 request = self._get_update_profile_request( 1179 client, 1180 endpoint=update_profile_endpoint, 1181 access_token=access_token, 1182 data=data, 1183 ) 1184 response = await client.send(request) 1185 1186 self._handle_request_error(response) 1187 1188 return response.json() 1189 1190 async def change_password( 1191 self, access_token: str, new_password: str 1192 ) -> FiefUserInfo: 1193 """ 1194 Change the user password with the Fief API using a valid access token. 1195 1196 **An access token with an ACR of at least level 1 is required.** 1197 1198 :param access_token: A valid access token. 1199 :param new_password: The new password. 1200 1201 **Example** 1202 1203 ```py 1204 userinfo = await fief.change_password("ACCESS_TOKEN", "herminetincture") 1205 ``` 1206 """ 1207 change_password_profile_endpoint = f"{self.base_url}/api/password" 1208 1209 async with self._get_httpx_client() as client: 1210 request = self._get_change_password_request( 1211 client, 1212 endpoint=change_password_profile_endpoint, 1213 access_token=access_token, 1214 new_password=new_password, 1215 ) 1216 response = await client.send(request) 1217 1218 self._handle_request_error(response) 1219 1220 return response.json() 1221 1222 async def email_change(self, access_token: str, email: str) -> FiefUserInfo: 1223 """ 1224 Request an email change with the Fief API using a valid access token. 1225 1226 The user will receive a verification code on this new email address. 1227 It shall be used with the method `email_verify` to complete the modification. 1228 1229 **An access token with an ACR of at least level 1 is required.** 1230 1231 :param access_token: A valid access token. 1232 :param email: The new email address. 1233 1234 **Example** 1235 1236 ```py 1237 userinfo = await fief.email_change("ACCESS_TOKEN", "anne@nantes.city") 1238 ``` 1239 """ 1240 email_change_endpoint = f"{self.base_url}/api/email/change" 1241 1242 async with self._get_httpx_client() as client: 1243 request = self._get_email_change_request( 1244 client, 1245 endpoint=email_change_endpoint, 1246 access_token=access_token, 1247 email=email, 1248 ) 1249 response = await client.send(request) 1250 1251 self._handle_request_error(response) 1252 1253 return response.json() 1254 1255 async def email_verify(self, access_token: str, code: str) -> FiefUserInfo: 1256 """ 1257 Verify the user email with the Fief API using a valid access token and verification code. 1258 1259 **An access token with an ACR of at least level 1 is required.** 1260 1261 :param access_token: A valid access token. 1262 :param code: The verification code received by email. 1263 1264 **Example** 1265 1266 ```py 1267 userinfo = fief.email_verify("ACCESS_TOKEN", "ABCDE") 1268 ``` 1269 """ 1270 email_verify_endpoint = f"{self.base_url}/api/email/verify" 1271 1272 async with self._get_httpx_client() as client: 1273 request = self._get_email_verify_request( 1274 client, 1275 endpoint=email_verify_endpoint, 1276 access_token=access_token, 1277 code=code, 1278 ) 1279 response = await client.send(request) 1280 1281 self._handle_request_error(response) 1282 1283 return response.json() 1284 1285 async def logout_url(self, redirect_uri: str) -> str: 1286 """ 1287 Returns a logout URL. If you redirect the user to this page, Fief will clear the session stored on its side. 1288 1289 **You're still responsible for clearing your own session mechanism if any.** 1290 1291 :param redirect_uri: A valid URL where the user will be redirected after the logout process: 1292 1293 **Example:** 1294 1295 ```py 1296 logout_url = await fief.logout_url("http://localhost:8000") 1297 ``` 1298 """ 1299 params = {"redirect_uri": redirect_uri} 1300 return f"{self.base_url}/logout?{urlencode(params)}" 1301 1302 @contextlib.asynccontextmanager 1303 async def _get_httpx_client(self): 1304 headers = {} 1305 if self.host is not None: 1306 headers["Host"] = self.host 1307 1308 async with httpx.AsyncClient( 1309 base_url=self.base_url, headers=headers, verify=self.verify, cert=self.cert 1310 ) as client: 1311 yield client 1312 1313 async def _get_openid_configuration(self) -> Dict[str, Any]: 1314 if self._openid_configuration is not None: 1315 return self._openid_configuration 1316 1317 async with self._get_httpx_client() as client: 1318 request = self._get_openid_configuration_request(client) 1319 response = await client.send(request) 1320 json = response.json() 1321 self._openid_configuration = json 1322 return json 1323 1324 async def _get_jwks(self) -> jwk.JWKSet: 1325 if self._jwks is not None: 1326 return self._jwks 1327 1328 jwks_uri = self._get_endpoint_url( 1329 await self._get_openid_configuration(), "jwks_uri" 1330 ) 1331 async with self._get_httpx_client() as client: 1332 response = await client.get(jwks_uri) 1333 self._jwks = jwk.JWKSet.from_json(response.text) 1334 return self._jwks 1335 1336 async def _auth_exchange_token( 1337 self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None 1338 ) -> FiefTokenResponse: 1339 token_endpoint = self._get_endpoint_url( 1340 await self._get_openid_configuration(), "token_endpoint" 1341 ) 1342 async with self._get_httpx_client() as client: 1343 request = self._get_auth_exchange_token_request( 1344 client, 1345 endpoint=token_endpoint, 1346 code=code, 1347 redirect_uri=redirect_uri, 1348 code_verifier=code_verifier, 1349 ) 1350 response = await client.send(request) 1351 1352 self._handle_request_error(response) 1353 1354 return response.json()
Async Fief authentication client.
926 def __init__( 927 self, 928 base_url: str, 929 client_id: str, 930 client_secret: Optional[str] = None, 931 *, 932 encryption_key: Optional[str] = None, 933 host: Optional[str] = None, 934 verify: VerifyTypes = True, 935 cert: Optional[CertTypes] = None, 936 ) -> None: 937 super().__init__( 938 base_url, 939 client_id, 940 client_secret, 941 encryption_key=encryption_key, 942 host=host, 943 verify=verify, 944 cert=cert, 945 )
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.
947 async def auth_url( 948 self, 949 redirect_uri: str, 950 *, 951 state: Optional[str] = None, 952 scope: Optional[List[str]] = None, 953 code_challenge: Optional[str] = None, 954 code_challenge_method: Optional[str] = None, 955 lang: Optional[str] = None, 956 extras_params: Optional[Mapping[str, str]] = None, 957 ) -> str: 958 """ 959 Return an authorization URL. 960 961 :param redirect_uri: Your callback URI where the user will be redirected after Fief authentication. 962 :param state: Optional string that will be returned back in the callback parameters to allow you to retrieve state information. 963 :param scope: Optional list of scopes to ask for. 964 :param code_challenge: Optional code challenge for 965 [PKCE process](https://docs.fief.dev/going-further/pkce/). 966 :param code_challenge_method: Method used to hash the PKCE code challenge. 967 :param lang: Optional parameter to set the user locale. 968 Should be a valid [RFC 3066](https://www.rfc-editor.org/rfc/rfc3066) language identifier, like `fr` or `pt-PT`. 969 If not provided, the user locale is determined by their browser settings. 970 :param extras_params: Optional dictionary containing [specific parameters](https://docs.fief.dev/going-further/authorize-url/). 971 972 **Example:** 973 974 ```py 975 auth_url = await fief.auth_url("http://localhost:8000/callback", scope=["openid"]) 976 ``` 977 """ 978 openid_configuration = await self._get_openid_configuration() 979 return self._auth_url( 980 openid_configuration, 981 redirect_uri, 982 state=state, 983 scope=scope, 984 code_challenge=code_challenge, 985 code_challenge_method=code_challenge_method, 986 lang=lang, 987 extras_params=extras_params, 988 )
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
orpt-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"])
990 async def auth_callback( 991 self, code: str, redirect_uri: str, *, code_verifier: Optional[str] = None 992 ) -> Tuple[FiefTokenResponse, FiefUserInfo]: 993 """ 994 Return a `FiefTokenResponse` and `FiefUserInfo` in exchange of an authorization code. 995 996 :param code: The authorization code. 997 :param redirect_uri: The exact same `redirect_uri` you passed to the authorization URL. 998 :param code_verifier: The raw 999 [PKCE](https://docs.fief.dev/going-further/pkce/) code used to generate the code challenge during authorization. 1000 1001 **Example:** 1002 1003 ```py 1004 tokens, userinfo = await fief.auth_callback("CODE", "http://localhost:8000/callback") 1005 ``` 1006 """ 1007 token_response = await self._auth_exchange_token( 1008 code, redirect_uri, code_verifier=code_verifier 1009 ) 1010 jwks = await self._get_jwks() 1011 userinfo = self._decode_id_token( 1012 token_response["id_token"], 1013 jwks, 1014 code=code, 1015 access_token=token_response.get("access_token"), 1016 ) 1017 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")
1019 async def auth_refresh_token( 1020 self, refresh_token: str, *, scope: Optional[List[str]] = None 1021 ) -> Tuple[FiefTokenResponse, FiefUserInfo]: 1022 """ 1023 Return fresh `FiefTokenResponse` and `FiefUserInfo` in exchange of a refresh token 1024 1025 :param refresh_token: A valid refresh token. 1026 :param scope: Optional list of scopes to ask for. 1027 If not provided, the access token will share the same list of scopes as requested the first time. 1028 Otherwise, it should be a subset of the original list of scopes. 1029 1030 **Example:** 1031 1032 ```py 1033 tokens, userinfo = await fief.auth_refresh_token("REFRESH_TOKEN") 1034 ``` 1035 """ 1036 token_endpoint = self._get_endpoint_url( 1037 await self._get_openid_configuration(), "token_endpoint" 1038 ) 1039 async with self._get_httpx_client() as client: 1040 request = self._get_auth_refresh_token_request( 1041 client, 1042 endpoint=token_endpoint, 1043 refresh_token=refresh_token, 1044 scope=scope, 1045 ) 1046 response = await client.send(request) 1047 1048 self._handle_request_error(response) 1049 1050 token_response = response.json() 1051 1052 jwks = await self._get_jwks() 1053 userinfo = self._decode_id_token( 1054 token_response["id_token"], 1055 jwks, 1056 access_token=token_response.get("access_token"), 1057 ) 1058 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")
1060 async def validate_access_token( 1061 self, 1062 access_token: str, 1063 *, 1064 required_scope: Optional[List[str]] = None, 1065 required_acr: Optional[FiefACR] = None, 1066 required_permissions: Optional[List[str]] = None, 1067 ) -> FiefAccessTokenInfo: 1068 """ 1069 Check if an access token is valid and optionally that it has a required list of scopes, 1070 or a required list of [permissions](https://docs.fief.dev/getting-started/access-control/). 1071 Returns a `FiefAccessTokenInfo`. 1072 1073 :param access_token: The access token to validate. 1074 :param required_scope: Optional list of scopes to check for. 1075 :param required_acr: Optional minimum ACR level required. 1076 Read more: https://docs.fief.dev/going-further/acr/ 1077 :param required_permissions: Optional list of permissions to check for. 1078 1079 **Example: Validate access token with required scopes** 1080 1081 ```py 1082 try: 1083 access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_scope=["required_scope"]) 1084 except FiefAccessTokenInvalid: 1085 print("Invalid access token") 1086 except FiefAccessTokenExpired: 1087 print("Expired access token") 1088 except FiefAccessTokenMissingScope: 1089 print("Missing required scope") 1090 1091 print(access_token_info) 1092 ``` 1093 1094 **Example: Validate access token with minimum ACR level** 1095 1096 ```py 1097 try: 1098 access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_acr=FiefACR.LEVEL_ONE) 1099 except FiefAccessTokenInvalid: 1100 print("Invalid access token") 1101 except FiefAccessTokenExpired: 1102 print("Expired access token") 1103 except FiefAccessTokenACRTooLow: 1104 print("ACR too low") 1105 1106 print(access_token_info) 1107 ``` 1108 1109 **Example: Validate access token with required permissions** 1110 1111 ```py 1112 try: 1113 access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_permissions=["castles:create", "castles:read"]) 1114 except FiefAccessTokenInvalid: 1115 print("Invalid access token") 1116 except FiefAccessTokenExpired: 1117 print("Expired access token") 1118 except FiefAccessTokenMissingPermission: 1119 print("Missing required permission") 1120 1121 print(access_token_info) 1122 ``` 1123 """ 1124 jwks = await self._get_jwks() 1125 return self._validate_access_token( 1126 access_token, 1127 jwks, 1128 required_scope=required_scope, 1129 required_acr=required_acr, 1130 required_permissions=required_permissions, 1131 )
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_acr: Optional minimum ACR level required. Read more: https://docs.fief.dev/going-further/acr/
- 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 minimum ACR level
try:
access_token_info = await fief.validate_access_token("ACCESS_TOKEN", required_acr=FiefACR.LEVEL_ONE)
except FiefAccessTokenInvalid:
print("Invalid access token")
except FiefAccessTokenExpired:
print("Expired access token")
except FiefAccessTokenACRTooLow:
print("ACR too low")
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)
1133 async def userinfo(self, access_token: str) -> FiefUserInfo: 1134 """ 1135 Return fresh `FiefUserInfo` from the Fief API using a valid access token. 1136 1137 :param access_token: A valid access token. 1138 1139 **Example:** 1140 1141 ```py 1142 userinfo = await fief.userinfo("ACCESS_TOKEN") 1143 ``` 1144 """ 1145 userinfo_endpoint = self._get_endpoint_url( 1146 await self._get_openid_configuration(), "userinfo_endpoint" 1147 ) 1148 async with self._get_httpx_client() as client: 1149 request = self._get_userinfo_request( 1150 client, endpoint=userinfo_endpoint, access_token=access_token 1151 ) 1152 response = await client.send(request) 1153 1154 self._handle_request_error(response) 1155 1156 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")
1158 async def update_profile( 1159 self, access_token: str, data: Dict[str, Any] 1160 ) -> FiefUserInfo: 1161 """ 1162 Update user information with the Fief API using a valid access token. 1163 1164 :param access_token: A valid access token. 1165 :param data: A dictionary containing the data to update. 1166 1167 **Example: Update user field** 1168 1169 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. 1170 1171 ```py 1172 userinfo = await fief.update_profile("ACCESS_TOKEN", { "fields": { "first_name": "Anne" } }) 1173 ``` 1174 """ 1175 update_profile_endpoint = f"{self.base_url}/api/profile" 1176 1177 async with self._get_httpx_client() as client: 1178 request = self._get_update_profile_request( 1179 client, 1180 endpoint=update_profile_endpoint, 1181 access_token=access_token, 1182 data=data, 1183 ) 1184 response = await client.send(request) 1185 1186 self._handle_request_error(response) 1187 1188 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 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" } })
1190 async def change_password( 1191 self, access_token: str, new_password: str 1192 ) -> FiefUserInfo: 1193 """ 1194 Change the user password with the Fief API using a valid access token. 1195 1196 **An access token with an ACR of at least level 1 is required.** 1197 1198 :param access_token: A valid access token. 1199 :param new_password: The new password. 1200 1201 **Example** 1202 1203 ```py 1204 userinfo = await fief.change_password("ACCESS_TOKEN", "herminetincture") 1205 ``` 1206 """ 1207 change_password_profile_endpoint = f"{self.base_url}/api/password" 1208 1209 async with self._get_httpx_client() as client: 1210 request = self._get_change_password_request( 1211 client, 1212 endpoint=change_password_profile_endpoint, 1213 access_token=access_token, 1214 new_password=new_password, 1215 ) 1216 response = await client.send(request) 1217 1218 self._handle_request_error(response) 1219 1220 return response.json()
Change the user password with the Fief API using a valid access token.
An access token with an ACR of at least level 1 is required.
Parameters
- access_token: A valid access token.
- new_password: The new password.
Example
userinfo = await fief.change_password("ACCESS_TOKEN", "herminetincture")
1222 async def email_change(self, access_token: str, email: str) -> FiefUserInfo: 1223 """ 1224 Request an email change with the Fief API using a valid access token. 1225 1226 The user will receive a verification code on this new email address. 1227 It shall be used with the method `email_verify` to complete the modification. 1228 1229 **An access token with an ACR of at least level 1 is required.** 1230 1231 :param access_token: A valid access token. 1232 :param email: The new email address. 1233 1234 **Example** 1235 1236 ```py 1237 userinfo = await fief.email_change("ACCESS_TOKEN", "anne@nantes.city") 1238 ``` 1239 """ 1240 email_change_endpoint = f"{self.base_url}/api/email/change" 1241 1242 async with self._get_httpx_client() as client: 1243 request = self._get_email_change_request( 1244 client, 1245 endpoint=email_change_endpoint, 1246 access_token=access_token, 1247 email=email, 1248 ) 1249 response = await client.send(request) 1250 1251 self._handle_request_error(response) 1252 1253 return response.json()
Request an email change with the Fief API using a valid access token.
The user will receive a verification code on this new email address.
It shall be used with the method email_verify
to complete the modification.
An access token with an ACR of at least level 1 is required.
Parameters
- access_token: A valid access token.
- email: The new email address.
Example
userinfo = await fief.email_change("ACCESS_TOKEN", "anne@nantes.city")
1255 async def email_verify(self, access_token: str, code: str) -> FiefUserInfo: 1256 """ 1257 Verify the user email with the Fief API using a valid access token and verification code. 1258 1259 **An access token with an ACR of at least level 1 is required.** 1260 1261 :param access_token: A valid access token. 1262 :param code: The verification code received by email. 1263 1264 **Example** 1265 1266 ```py 1267 userinfo = fief.email_verify("ACCESS_TOKEN", "ABCDE") 1268 ``` 1269 """ 1270 email_verify_endpoint = f"{self.base_url}/api/email/verify" 1271 1272 async with self._get_httpx_client() as client: 1273 request = self._get_email_verify_request( 1274 client, 1275 endpoint=email_verify_endpoint, 1276 access_token=access_token, 1277 code=code, 1278 ) 1279 response = await client.send(request) 1280 1281 self._handle_request_error(response) 1282 1283 return response.json()
Verify the user email with the Fief API using a valid access token and verification code.
An access token with an ACR of at least level 1 is required.
Parameters
- access_token: A valid access token.
- code: The verification code received by email.
Example
userinfo = fief.email_verify("ACCESS_TOKEN", "ABCDE")
1285 async def logout_url(self, redirect_uri: str) -> str: 1286 """ 1287 Returns a logout URL. If you redirect the user to this page, Fief will clear the session stored on its side. 1288 1289 **You're still responsible for clearing your own session mechanism if any.** 1290 1291 :param redirect_uri: A valid URL where the user will be redirected after the logout process: 1292 1293 **Example:** 1294 1295 ```py 1296 logout_url = await fief.logout_url("http://localhost:8000") 1297 ``` 1298 """ 1299 params = {"redirect_uri": redirect_uri} 1300 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
- encryption_key
- host
- verify
- cert
55class FiefTokenResponse(TypedDict): 56 """ 57 Typed dictionary containing the tokens and related information returned by Fief after a successful authentication. 58 """ 59 60 access_token: str 61 """Access token you can use to call the Fief API.""" 62 id_token: str 63 """ID token containing user information.""" 64 token_type: str 65 """Type of token, usually `bearer`.""" 66 expires_in: int 67 """Number of seconds after which the tokens will expire.""" 68 refresh_token: Optional[str] 69 """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.
Token provided only if scope offline_access
was granted. Allows you to retrieve fresh tokens using the Fief.auth_refresh_token
method.
72class FiefAccessTokenInfo(TypedDict): 73 """ 74 Typed dictionary containing information about the access token. 75 76 **Example:** 77 78 ```json 79 { 80 "id": "aeeb8bfa-e8f4-4724-9427-c3d5af66190e", 81 "scope": ["openid", "required_scope"], 82 "acr": "1", 83 "permissions": ["castles:read", "castles:create", "castles:update", "castles:delete"], 84 "access_token": "ACCESS_TOKEN", 85 } 86 ``` 87 """ 88 89 id: uuid.UUID 90 """ID of the user.""" 91 scope: List[str] 92 """List of granted scopes for this access token.""" 93 acr: FiefACR 94 """Level of Authentication Context class Reference.""" 95 permissions: List[str] 96 """List of [granted permissions](https://docs.fief.dev/getting-started/access-control/) for this user.""" 97 access_token: str 98 """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"],
"acr": "1",
"permissions": ["castles:read", "castles:create", "castles:update", "castles:delete"],
"access_token": "ACCESS_TOKEN",
}
101class FiefUserInfo(TypedDict): 102 """ 103 Dictionary containing user information. 104 105 **Example:** 106 107 ```json 108 { 109 "sub": "aeeb8bfa-e8f4-4724-9427-c3d5af66190e", 110 "email": "anne@bretagne.duchy", 111 "tenant_id": "c91ecb7f-359c-4244-8385-51ecd6c0d06b", 112 "fields": { 113 "first_name": "Anne", 114 "last_name": "De Bretagne" 115 } 116 } 117 ``` 118 """ 119 120 sub: str 121 """ 122 ID of the user. 123 """ 124 email: str 125 """ 126 Email address of the user. 127 """ 128 tenant_id: str 129 """ 130 ID of the [tenant](https://docs.fief.dev/getting-started/tenants/) associated to the user. 131 """ 132 fields: Dict[str, Any] 133 """ 134 [User fields](https://docs.fief.dev/getting-started/user-fields/) values for this user, indexed by their slug. 135 """
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"
}
}
Base Fief client error.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args
164class FiefAccessTokenACRTooLow(FiefError): 165 """The access token doesn't meet the minimum ACR level."""
The access token doesn't meet the minimum ACR level.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args
The access token is expired.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args
168class FiefAccessTokenMissingPermission(FiefError): 169 """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
- args
160class FiefAccessTokenMissingScope(FiefError): 161 """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
- args
The access token is invalid.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args
The ID token is invalid.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args
142class FiefRequestError(FiefError): 143 """The request to Fief server resulted in an error.""" 144 145 def __init__(self, status_code: int, detail: str) -> None: 146 self.status_code = status_code 147 self.detail = detail 148 self.message = f"[{status_code}] - {detail}" 149 super().__init__(self.message)
The request to Fief server resulted in an error.
Inherited Members
- builtins.BaseException
- with_traceback
- args