async def test_write_token(jwt_strategy: JWTStrategy, user): token = await jwt_strategy.write_token(user) decoded = decode_jwt(token, jwt_strategy.secret, audience=jwt_strategy.token_audience) assert decoded["user_id"] == str(user.id)
def test_generate_decode_jwt(secret: SecretType): audience = "TEST_AUDIENCE" data = {"foo": "bar", "aud": audience} jwt = generate_jwt(data, secret, 3600) decoded = decode_jwt(jwt, secret, [audience]) assert decoded["foo"] == "bar" assert decoded["aud"] == audience
async def verify(self, token: str, request: Optional[Request] = None) -> models.UD: """ Validate a verification request. Changes the is_verified flag of the user to True. Triggers the on_after_verify handler on success. :param token: The verification token generated by request_verify. :param request: Optional FastAPI request that triggered the operation, defaults to None. :raises InvalidVerifyToken: The token is invalid or expired. :raises UserAlreadyVerified: The user is already verified. :return: The verified user. """ try: data = decode_jwt( token, self.verification_token_secret, [self.verification_token_audience], ) except jwt.PyJWTError: raise InvalidVerifyToken() try: user_id = data["user_id"] email = data["email"] except KeyError: raise InvalidVerifyToken() try: user = await self.get_by_email(email) except UserNotExists: raise InvalidVerifyToken() try: user_uuid = UUID4(user_id) except ValueError: raise InvalidVerifyToken() if user_uuid != user.id: raise InvalidVerifyToken() if user.is_verified: raise UserAlreadyVerified() verified_user = await self._update(user, {"is_verified": True}) await self.on_after_verify(verified_user, request) return verified_user
async def callback( request: Request, response: Response, access_token_state: Tuple[OAuth2Token, str] = Depends( oauth2_authorize_callback ), user_manager: BaseUserManager[models.UC, models.UD] = Depends(get_user_manager), strategy: Strategy[models.UC, models.UD] = Depends(backend.get_strategy), ): token, state = access_token_state account_id, account_email = await oauth_client.get_id_email( token["access_token"] ) try: decode_jwt(state, state_secret, [STATE_TOKEN_AUDIENCE]) except jwt.DecodeError: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST) new_oauth_account = models.BaseOAuthAccount( oauth_name=oauth_client.name, access_token=token["access_token"], expires_at=token.get("expires_at"), refresh_token=token.get("refresh_token"), account_id=account_id, account_email=account_email, ) user = await user_manager.oauth_callback(new_oauth_account, request) if not user.is_active: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.LOGIN_BAD_CREDENTIALS, ) # Authenticate return await backend.login(strategy, user, response)
async def test_user_active(self, user_manager: UserManagerMock, user: UserDB): await user_manager.forgot_password(user) assert user_manager.on_after_forgot_password.called is True actual_user = user_manager.on_after_forgot_password.call_args[0][0] actual_token = user_manager.on_after_forgot_password.call_args[0][1] assert actual_user.id == user.id decoded_token = decode_jwt( actual_token, user_manager.reset_password_token_secret, audience=[user_manager.reset_password_token_audience], ) assert decoded_token["user_id"] == str(user.id)
async def test_user_active_not_verified(self, user_manager: UserManagerMock, user: UserDB): await user_manager.request_verify(user) assert user_manager.on_after_request_verify.called is True actual_user = user_manager.on_after_request_verify.call_args[0][0] actual_token = user_manager.on_after_request_verify.call_args[0][1] assert actual_user.id == user.id decoded_token = decode_jwt( actual_token, user_manager.verification_token_secret, audience=[user_manager.verification_token_audience], ) assert decoded_token["user_id"] == str(user.id) assert decoded_token["email"] == str(user.email)
async def reset_password( self, token: str, password: str, request: Optional[Request] = None ) -> models.UD: """ Reset the password of a user. Triggers the on_after_reset_password handler on success. :param token: The token generated by forgot_password. :param password: The new password to set. :param request: Optional FastAPI request that triggered the operation, defaults to None. :raises InvalidResetPasswordToken: The token is invalid or expired. :raises UserInactive: The user is inactive. :raises InvalidPasswordException: The password is invalid. :return: The user with updated password. """ try: data = decode_jwt( token, self.reset_password_token_secret, [self.reset_password_token_audience], ) except jwt.PyJWTError: raise InvalidResetPasswordToken() try: user_id = data["user_id"] except KeyError: raise InvalidResetPasswordToken() try: user_uuid = UUID4(user_id) except ValueError: raise InvalidResetPasswordToken() user = await self.get(user_uuid) if not user.is_active: raise UserInactive() updated_user = await self._update(user, {"password": password}) await self.on_after_reset_password(user, request) return updated_user
async def read_token( self, token: Optional[str], user_manager: BaseUserManager[models.UC, models.UD] ) -> Optional[models.UD]: if token is None: return None try: data = decode_jwt(token, self.secret, self.token_audience) user_id = data.get("user_id") if user_id is None: return None except jwt.PyJWTError: return None try: user_uiid = UUID4(user_id) return await user_manager.get(user_uiid) except ValueError: return None except UserNotExists: return None