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

Refresh token #404

Merged
merged 39 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
6b10d44
Add client and service
seallard Mar 6, 2024
1ff1327
Finish skeleton
seallard Mar 6, 2024
d9bbb82
Formatting
seallard Mar 6, 2024
148e820
Naming
seallard Mar 6, 2024
f5cd656
Finish encryption service
seallard Mar 7, 2024
15e86ad
Refactor
seallard Mar 7, 2024
2a210cb
Add test
seallard Mar 7, 2024
a6305c4
Use different AES mode
seallard Mar 7, 2024
f225eae
Add endpoint
seallard Mar 7, 2024
0d1f68a
Naming
seallard Mar 7, 2024
16adc46
Merge branch 'master' into add-oauth-client
seallard Mar 7, 2024
e7aa1d0
Naming
seallard Mar 7, 2024
027427e
Add type hint
seallard Mar 7, 2024
076cb1e
Add test
seallard Mar 7, 2024
a89ee73
Test service
seallard Mar 7, 2024
8654704
Test wip
seallard Mar 7, 2024
6b42c6c
Retrieve user email from google
seallard Mar 7, 2024
8c3549e
Formatting
seallard Mar 7, 2024
dcf3bfb
Naming
seallard Mar 7, 2024
500cca5
Simplify signature
seallard Mar 7, 2024
f46036d
Fix test
seallard Mar 8, 2024
a05f390
Clean diff
seallard Mar 8, 2024
9c7715d
Formatting
seallard Mar 8, 2024
19d453f
Cleaning
seallard Mar 8, 2024
b1f21b6
Add alembic revision
seallard Mar 8, 2024
64359bb
Formatting
seallard Mar 8, 2024
564242c
Catch exception
seallard Mar 8, 2024
3dba75a
Catch correct exception
seallard Mar 8, 2024
0eaee6a
Disable authentication for auth endpoint
seallard Mar 8, 2024
b5ae31c
Formatting
seallard Mar 8, 2024
13bc909
Improve test
seallard Mar 8, 2024
d93fd02
Naming
seallard Mar 8, 2024
12dc894
Add docstring
seallard Mar 8, 2024
961a43f
Add refresh endpoint
seallard Mar 8, 2024
7e6aade
Add test
seallard Mar 8, 2024
1f9fcaf
Improve test
seallard Mar 8, 2024
5e519a0
Fix comment
seallard Mar 8, 2024
3423a6d
Remove unnecessary exception
seallard Mar 8, 2024
3d40af6
Merge branch 'master' into refresh-token
seallard Mar 11, 2024
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
20 changes: 20 additions & 0 deletions tests/integration/services/test_authentication_service.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from requests_mock import Mocker

from trailblazer.services.authentication_service.authentication_service import AuthenticationService
from trailblazer.services.encryption_service.encryption_service import EncryptionService
from trailblazer.store.models import User


Expand All @@ -16,3 +17,22 @@ def test_exchange_code(authentication_service: AuthenticationService, user_email
# THEN the refresh token is stored on the user
user: User = authentication_service.store.get_user(user_email)
assert user.refresh_token


def test_refresh_access_token(
authentication_service: AuthenticationService,
encryption_service: EncryptionService,
user_email: str,
):
# GIVEN an encrypted refresh token
encrypted_refresh_token: str = encryption_service.encrypt("refresh_token")

# GIVEN an existing user with the refresh token
user: User = authentication_service.store.get_user(user_email)
user.refresh_token = encrypted_refresh_token

# WHEN refreshing the access token
token: str = authentication_service.refresh_access_token(user.id)

# THEN an access token is returned
assert token
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from pydantic import BaseModel


class RefreshAccessTokenRequest(BaseModel):
client_id: str
client_secret: str
refresh_token: str
grant_type: str = "refresh_token"
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import requests

from trailblazer.clients.authentication_client.dtos.refresh_token_request import (
RefreshAccessTokenRequest,
)
from trailblazer.clients.authentication_client.dtos.tokens_request import GetTokensRequest
from trailblazer.clients.authentication_client.dtos.tokens_response import TokensResponse
from trailblazer.clients.authentication_client.exceptions import GoogleOAuthClientError
Expand Down Expand Up @@ -29,3 +32,19 @@ def get_tokens(self, authorization_code: str) -> TokensResponse:
raise GoogleOAuthClientError(response.text)

return TokensResponse.model_validate(response.json())

def get_access_token(self, refresh_token: str) -> str:
"""Use refresh token to get a new access token."""
request = RefreshAccessTokenRequest(
client_id=self.client_id,
client_secret=self.client_secret,
refresh_token=refresh_token,
)
data: str = request.model_dump_json()

response = requests.post(self.token_uri, data=data)

if not response.ok:
raise GoogleOAuthClientError(response.text)

return response.json()["access_token"]
14 changes: 13 additions & 1 deletion trailblazer/server/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from trailblazer.services.authentication_service.authentication_service import AuthenticationService
from trailblazer.services.authentication_service.exceptions import AuthenticationError
from trailblazer.services.job_service import JobService
from trailblazer.store.models import Info
from trailblazer.store.models import Info, User

blueprint = Blueprint("api", __name__, url_prefix="/api/v1")

Expand Down Expand Up @@ -82,6 +82,18 @@ def authenticate(auth_service: AuthenticationService = Provide[Container.auth_se
return jsonify("User not allowed"), HTTPStatus.FORBIDDEN


@blueprint.route("/auth/refresh", methods=["GET"])
@inject
def refresh_token(auth_service: AuthenticationService = Provide[Container.auth_service]):
"""Refresh access token."""
user: User = g.current_user
try:
token: str = auth_service.refresh_access_token(user.id)
return jsonify({"access_token": token}), HTTPStatus.OK
except AuthenticationError:
seallard marked this conversation as resolved.
Show resolved Hide resolved
return jsonify("User not allowed"), HTTPStatus.FORBIDDEN


@blueprint.route("/analyses", methods=["GET"])
@inject
def get_analyses(analysis_service: AnalysisService = Provide[Container.analysis_service]):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,10 @@ def authenticate(self, authorization_code: str) -> str:
self.store.update_user_token(user_id=user.id, refresh_token=encrypted_token)

return tokens.access_token

def refresh_access_token(self, user_id: int) -> str:
"""Refresh the users access token."""
user: User = self.store.get_user_by_id(user_id)
refresh_token: str = self.encryption_service.decrypt(user.refresh_token)
access_token: str = self.google_oauth_client.get_access_token(refresh_token)
return access_token
Loading