Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add AuthOtpResponse #419

Merged
merged 4 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions gotrue/_async/gotrue_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
model_dump,
model_dump_json,
model_validate,
parse_auth_otp_response,
parse_auth_response,
parse_sso_response,
parse_user_response,
Expand All @@ -46,6 +47,7 @@
AuthMFAListFactorsResponse,
AuthMFAUnenrollResponse,
AuthMFAVerifyResponse,
AuthOtpResponse,
AuthResponse,
CodeExchangeParams,
DecodedJWTDict,
Expand Down Expand Up @@ -269,19 +271,19 @@
If you have built an organization-specific login page, you can use the
organization's SSO Identity Provider UUID directly instead.
"""
self._remove_session()
provider_id = credentials.get("provider_id")
domain = credentials.get("domain")
options = credentials.get("options", {})
redirect_to = options.get("redirect_to")
captcha_token = options.get("captcha_token")

Check warning on line 279 in gotrue/_async/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_async/gotrue_client.py#L274-L279

Added lines #L274 - L279 were not covered by tests
# HTTPX currently does not follow redirects: https://www.python-httpx.org/compatibility/
# Additionally, unlike the JS client, Python is a server side language and it's not possible
# to automatically redirect in browser for hte user
skip_http_redirect = options.get("skip_http_redirect", True)

Check warning on line 283 in gotrue/_async/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_async/gotrue_client.py#L283

Added line #L283 was not covered by tests

if domain:
return self._request(

Check warning on line 286 in gotrue/_async/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_async/gotrue_client.py#L285-L286

Added lines #L285 - L286 were not covered by tests
"POST",
"sso",
body={
Expand All @@ -294,8 +296,8 @@
redirect_to=redirect_to,
xform=parse_sso_response,
)
if provider_id:
return self._request(

Check warning on line 300 in gotrue/_async/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_async/gotrue_client.py#L299-L300

Added lines #L299 - L300 were not covered by tests
"POST",
"sso",
body={
Expand All @@ -308,7 +310,7 @@
redirect_to=redirect_to,
xform=parse_sso_response,
)
raise AuthInvalidCredentialsError(

Check warning on line 313 in gotrue/_async/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_async/gotrue_client.py#L313

Added line #L313 was not covered by tests
"You must provide either a domain or provider_id"
)

Expand All @@ -334,30 +336,30 @@
return OAuthResponse(provider=provider, url=url)

async def link_identity(self, credentials):
provider = credentials.get("provider")
options = credentials.get("options", {})
redirect_to = options.get("redirect_to")
scopes = options.get("scopes")
params = options.get("query_params", {})
if redirect_to:
params["redirect_to"] = redirect_to
if scopes:
params["scopes"] = scopes
params["skip_browser_redirect"] = True

Check warning on line 348 in gotrue/_async/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_async/gotrue_client.py#L339-L348

Added lines #L339 - L348 were not covered by tests

url = await self._get_url_for_provider(provider, params)
return OAuthResponse(provider=provider, url=url)

Check warning on line 351 in gotrue/_async/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_async/gotrue_client.py#L350-L351

Added lines #L350 - L351 were not covered by tests

async def get_user_identities(self):
response = self.get_user()
return (

Check warning on line 355 in gotrue/_async/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_async/gotrue_client.py#L354-L355

Added lines #L354 - L355 were not covered by tests
IdentitiesResponse(identities=response.user.identities)
if response.user
else AuthSessionMissingError()
)

async def unlink_identity(self, identity):
return await self._request(

Check warning on line 362 in gotrue/_async/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_async/gotrue_client.py#L362

Added line #L362 was not covered by tests
"POST",
f"/user/identities/{identity.id}",
)
Expand All @@ -365,7 +367,7 @@
async def sign_in_with_otp(
self,
credentials: SignInWithPasswordlessCredentials,
) -> AuthResponse:
) -> AuthOtpResponse:
"""
Log in a user using magiclink or a one-time password (OTP).

Expand Down Expand Up @@ -399,7 +401,7 @@
},
},
redirect_to=email_redirect_to,
xform=parse_auth_response,
xform=parse_auth_otp_response,
)
if phone:
return await self._request(
Expand All @@ -413,7 +415,7 @@
"captcha_token": captcha_token,
},
},
xform=parse_auth_response,
xform=parse_auth_otp_response,
)
raise AuthInvalidCredentialsError(
"You must provide either an email or phone number"
Expand Down
8 changes: 5 additions & 3 deletions gotrue/_sync/gotrue_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
model_dump,
model_dump_json,
model_validate,
parse_auth_otp_response,
parse_auth_response,
parse_sso_response,
parse_user_response,
Expand All @@ -46,6 +47,7 @@
AuthMFAListFactorsResponse,
AuthMFAUnenrollResponse,
AuthMFAVerifyResponse,
AuthOtpResponse,
AuthResponse,
CodeExchangeParams,
DecodedJWTDict,
Expand Down Expand Up @@ -269,19 +271,19 @@
If you have built an organization-specific login page, you can use the
organization's SSO Identity Provider UUID directly instead.
"""
self._remove_session()
provider_id = credentials.get("provider_id")
domain = credentials.get("domain")
options = credentials.get("options", {})
redirect_to = options.get("redirect_to")
captcha_token = options.get("captcha_token")

Check warning on line 279 in gotrue/_sync/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_sync/gotrue_client.py#L274-L279

Added lines #L274 - L279 were not covered by tests
# HTTPX currently does not follow redirects: https://www.python-httpx.org/compatibility/
# Additionally, unlike the JS client, Python is a server side language and it's not possible
# to automatically redirect in browser for hte user
skip_http_redirect = options.get("skip_http_redirect", True)

Check warning on line 283 in gotrue/_sync/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_sync/gotrue_client.py#L283

Added line #L283 was not covered by tests

if domain:
return self._request(

Check warning on line 286 in gotrue/_sync/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_sync/gotrue_client.py#L285-L286

Added lines #L285 - L286 were not covered by tests
"POST",
"sso",
body={
Expand All @@ -294,8 +296,8 @@
redirect_to=redirect_to,
xform=parse_sso_response,
)
if provider_id:
return self._request(

Check warning on line 300 in gotrue/_sync/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_sync/gotrue_client.py#L299-L300

Added lines #L299 - L300 were not covered by tests
"POST",
"sso",
body={
Expand All @@ -308,7 +310,7 @@
redirect_to=redirect_to,
xform=parse_sso_response,
)
raise AuthInvalidCredentialsError(

Check warning on line 313 in gotrue/_sync/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_sync/gotrue_client.py#L313

Added line #L313 was not covered by tests
"You must provide either a domain or provider_id"
)

Expand All @@ -334,30 +336,30 @@
return OAuthResponse(provider=provider, url=url)

def link_identity(self, credentials):
provider = credentials.get("provider")
options = credentials.get("options", {})
redirect_to = options.get("redirect_to")
scopes = options.get("scopes")
params = options.get("query_params", {})
if redirect_to:
params["redirect_to"] = redirect_to
if scopes:
params["scopes"] = scopes
params["skip_browser_redirect"] = True

Check warning on line 348 in gotrue/_sync/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_sync/gotrue_client.py#L339-L348

Added lines #L339 - L348 were not covered by tests

url = self._get_url_for_provider(provider, params)
return OAuthResponse(provider=provider, url=url)

Check warning on line 351 in gotrue/_sync/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_sync/gotrue_client.py#L350-L351

Added lines #L350 - L351 were not covered by tests

def get_user_identities(self):
response = self.get_user()
return (

Check warning on line 355 in gotrue/_sync/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_sync/gotrue_client.py#L354-L355

Added lines #L354 - L355 were not covered by tests
IdentitiesResponse(identities=response.user.identities)
if response.user
else AuthSessionMissingError()
)

def unlink_identity(self, identity):
return self._request(

Check warning on line 362 in gotrue/_sync/gotrue_client.py

View check run for this annotation

Codecov / codecov/patch

gotrue/_sync/gotrue_client.py#L362

Added line #L362 was not covered by tests
"POST",
f"/user/identities/{identity.id}",
)
Expand All @@ -365,7 +367,7 @@
def sign_in_with_otp(
self,
credentials: SignInWithPasswordlessCredentials,
) -> AuthResponse:
) -> AuthOtpResponse:
"""
Log in a user using magiclink or a one-time password (OTP).

Expand Down Expand Up @@ -399,7 +401,7 @@
},
},
redirect_to=email_redirect_to,
xform=parse_auth_response,
xform=parse_auth_otp_response,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (llm): Switching the transformation function to parse_auth_otp_response for OTP sign-ins is a logical step following the introduction of AuthOtpResponse. This change ensures that the response parsing is aligned with the expected response structure. It's a good practice to verify that the transformation function correctly handles all possible response variations to avoid runtime errors.

J0 marked this conversation as resolved.
Show resolved Hide resolved
)
if phone:
return self._request(
Expand All @@ -413,7 +415,7 @@
"captcha_token": captcha_token,
},
},
xform=parse_auth_response,
xform=parse_auth_otp_response,
)
raise AuthInvalidCredentialsError(
"You must provide either an email or phone number"
Expand Down
5 changes: 5 additions & 0 deletions gotrue/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from .errors import AuthApiError, AuthError, AuthRetryableError, AuthUnknownError
from .types import (
AuthOtpResponse,
AuthResponse,
GenerateLinkProperties,
GenerateLinkResponse,
Expand Down Expand Up @@ -72,6 +73,10 @@
return AuthResponse(session=session, user=user)


def parse_auth_otp_response(data: Any) -> AuthOtpResponse:
return model_validate(AuthOtpResponse, data)

Check warning on line 77 in gotrue/helpers.py

View check run for this annotation

Codecov / codecov/patch

gotrue/helpers.py#L77

Added line #L77 was not covered by tests


def parse_link_response(data: Any) -> GenerateLinkResponse:
properties = GenerateLinkProperties(
action_link=data.get("action_link"),
Expand All @@ -93,7 +98,7 @@


def parse_sso_response(data: Any) -> SSOResponse:
return model_validate(SSOResponse, data)

Check warning on line 101 in gotrue/helpers.py

View check run for this annotation

Codecov / codecov/patch

gotrue/helpers.py#L101

Added line #L101 was not covered by tests


def get_error_message(error: Any) -> str:
Expand Down
6 changes: 6 additions & 0 deletions gotrue/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ class AuthResponse(BaseModel):
session: Union[Session, None] = None


class AuthOtpResponse(BaseModel):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (llm): Introducing AuthOtpResponse as a new response type is a good design decision for handling OTP-specific responses. However, it's important to ensure that the message_id field is adequately documented, including its purpose and any relevant constraints or expected values. This will help maintain clarity and ease of use for developers interacting with this part of the API.

user: None = None
session: None = None
message_id: Union[str, None] = None


class OAuthResponse(BaseModel):
provider: Provider
url: str
Expand Down
Loading