1414
1515from __future__ import annotations
1616
17- from supertokens_python .recipe .thirdparty .provider import Provider
17+ from typing import Dict , Any , Optional
18+
19+ from supertokens_python .recipe .thirdparty .provider import (
20+ ProviderConfigForClient ,
21+ ProviderInput ,
22+ Provider ,
23+ )
1824from .custom import GenericProvider , NewProvider
19- from ..provider import Provider , ProviderInput
25+
26+ from .utils import do_get_request
27+ from ..types import RawUserInfoFromProvider , UserInfo , UserInfoEmail
2028
2129
2230class BitbucketImpl (GenericProvider ):
23- pass
31+ async def get_config_for_client_type (
32+ self , client_type : Optional [str ], user_context : Dict [str , Any ]
33+ ) -> ProviderConfigForClient :
34+ config = await super ().get_config_for_client_type (client_type , user_context )
35+
36+ if config .scope is None :
37+ config .scope = ["account" , "email" ]
38+
39+ return config
40+
41+ async def get_user_info (
42+ self , oauth_tokens : Dict [str , Any ], user_context : Dict [str , Any ]
43+ ) -> UserInfo :
44+ _ = user_context
45+ access_token = oauth_tokens .get ("access_token" )
46+ if access_token is None :
47+ raise Exception ("Access token not found" )
48+
49+ headers = {
50+ "Authorization" : f"Bearer { access_token } " ,
51+ }
52+
53+ raw_user_info_from_provider = RawUserInfoFromProvider ({}, {})
54+
55+ user_info_from_access_token = await do_get_request (
56+ "https://api.bitbucket.org/2.0/user" ,
57+ query_params = None ,
58+ headers = headers ,
59+ )
60+
61+ raw_user_info_from_provider .from_user_info_api = user_info_from_access_token
62+
63+ user_info_from_email = await do_get_request (
64+ "https://api.bitbucket.org/2.0/user/emails" ,
65+ query_params = None ,
66+ headers = headers ,
67+ )
68+
69+ if raw_user_info_from_provider .from_id_token_payload is None :
70+ # Actually this should never happen but python type
71+ # checker is not agreeing so doing this:
72+ raw_user_info_from_provider .from_id_token_payload = {}
73+
74+ raw_user_info_from_provider .from_id_token_payload [
75+ "email"
76+ ] = user_info_from_email
77+
78+ email = None
79+ is_verified = False
80+ for email_info in user_info_from_email .values ():
81+ if email_info ["is_primary" ]:
82+ email = email_info ["email" ]
83+ is_verified = email_info ["is_confirmed" ]
84+
85+ return UserInfo (
86+ third_party_user_id = raw_user_info_from_provider .from_user_info_api ["uuid" ],
87+ email = None if email is None else UserInfoEmail (email , is_verified ),
88+ raw_user_info_from_provider = raw_user_info_from_provider ,
89+ )
2490
2591
2692def Bitbucket (input : ProviderInput ) -> Provider : # pylint: disable=redefined-builtin
@@ -35,7 +101,9 @@ def Bitbucket(input: ProviderInput) -> Provider: # pylint: disable=redefined-bu
35101 if input .config .token_endpoint is None :
36102 input .config .token_endpoint = "https://bitbucket.org/site/oauth2/access_token"
37103
38- if input .config .user_info_endpoint is None :
39- input .config .user_info_endpoint = "https://api.bitbucket.org/2.0/user"
104+ if input .config .authorization_endpoint_query_params is None :
105+ input .config .authorization_endpoint_query_params = {
106+ "audience" : "api.atlassian.com" ,
107+ }
40108
41109 return NewProvider (input , BitbucketImpl )
0 commit comments