aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gn_auth/auth/authentication/oauth2/grants/refresh_token_grant.py51
-rw-r--r--gn_auth/auth/authentication/oauth2/server.py2
2 files changed, 53 insertions, 0 deletions
diff --git a/gn_auth/auth/authentication/oauth2/grants/refresh_token_grant.py b/gn_auth/auth/authentication/oauth2/grants/refresh_token_grant.py
new file mode 100644
index 0000000..fd6804d
--- /dev/null
+++ b/gn_auth/auth/authentication/oauth2/grants/refresh_token_grant.py
@@ -0,0 +1,51 @@
+"""RefreshTokenGrant: Useful for refreshing the tokens."""
+from pymonad.maybe import Nothing
+from flask import current_app as app
+from authlib.oauth2.rfc6749 import grants
+
+from gn_auth.auth.errors import NotFoundError
+from gn_auth.auth.db.sqlite3 import connection
+from gn_auth.auth.authentication.users import user_by_id
+from gn_auth.auth.authentication.oauth2.models.jwtrefreshtoken import (
+ load_refresh_token,
+ revoke_refresh_token,
+ is_refresh_token_valid)
+
+
+class RefreshTokenGrant(grants.RefreshTokenGrant):
+ """Useful for refreshing tokens"""
+ INCLUDE_NEW_REFRESH_TOKEN = True
+ TOKEN_ENDPOINT_AUTH_METHODS = ['client_secret_basic', 'client_secret_post']
+ DEFAULT_EXPIRES_IN = 432000 # 5 days
+
+ def authenticate_refresh_token(self, refresh_token):
+ """
+ Check that the refresh token is good.
+
+ Maybe also check that token has not been used before: if it has, revoke
+ any new tokens and refresh tokens issued from that.
+ """
+ with connection(app.config["AUTH_DB"]) as conn:
+ return load_refresh_token(
+ conn, refresh_token
+ ).then(
+ lambda _tok: (
+ _tok if is_refresh_token_valid(_tok, self.request.client)
+ else Nothing)
+ ).maybe(None, lambda _tok: _tok)
+
+ def authenticate_user(self, credential):
+ """Check that user is valid for given token."""
+ with connection(app.config["AUTH_DB"]) as conn:
+ try:
+ return user_by_id(conn, credential.user.user_id)
+ except NotFoundError as _nfe:
+ return None
+
+ return None
+
+ def revoke_old_credential(self, credential):
+ """Revoke any old refresh token after issuing new refresh token."""
+ with connection(app.config["AUTH_DB"]) as conn:
+ if credential.parent_of is not None:
+ revoke_refresh_token(conn, credential)
diff --git a/gn_auth/auth/authentication/oauth2/server.py b/gn_auth/auth/authentication/oauth2/server.py
index 70a0e51..8b65aa9 100644
--- a/gn_auth/auth/authentication/oauth2/server.py
+++ b/gn_auth/auth/authentication/oauth2/server.py
@@ -16,6 +16,7 @@ from .models.oauth2token import OAuth2Token, save_token
from .models.jwtrefreshtoken import JWTRefreshToken, save_refresh_token
from .grants.password_grant import PasswordGrant
+from .grants.refresh_token_grant import RefreshTokenGrant
from .grants.authorisation_code_grant import AuthorisationCodeGrant
from .grants.jwt_bearer_grant import JWTBearerGrant, JWTBearerTokenGenerator
@@ -83,6 +84,7 @@ def setup_oauth2_server(app: Flask) -> None:
server.register_token_generator(
"urn:ietf:params:oauth:grant-type:jwt-bearer",
JWTBearerTokenGenerator(app.config["SSL_PRIVATE_KEY"]))
+ server.register_grant(RefreshTokenGrant)
# register endpoints
server.register_endpoint(RevocationEndpoint)