Commit fb49b50e authored by Alp Deniz Ogut's avatar Alp Deniz Ogut
Browse files

Refresh token is optional

parent 017e20ac
Pipeline #3362 passed with stage
in 3 minutes and 36 seconds
Showing with 2 additions and 2 deletions
+2 -2
%% Cell type:code id: tags:
``` python
%load_ext autoreload
%autoreload 2
# default_exp plugin.authenticators.oauth
```
%% Cell type:code id: tags:
``` python
# export
# hide
import abc
from time import sleep
from pymemri.plugin.states import RUN_USER_ACTION_NEEDED, RUN_USER_ACTION_COMPLETED
```
%% Cell type:markdown id: tags:
## OAuth Authenticator
OAuth Authenticator provides an easy interface to setup standard Open Authorization (OAuth) with 3rd party services.
Simply calling `authenticate()` should load the related account with required credentials.
Inheriting class should implement:
- get_oauth_url() to setup OAuth endpoint
- get_tokens_from_code() to retrieve tokens from the service with returned OAuth code
- refresh_tokens() to get new token pairs
%% Cell type:code id: tags:
``` python
# export
# hide
class OAuthAuthenticator(metaclass=abc.ABCMeta):
SLEEP_INTERVAL = 1.0
def __init__(self, client, pluginRun):
self.client = client
self.pluginRun = pluginRun
self.isTest = False
def authenticate(self):
tokens = None
try:
if not self.pluginRun.account[0].refreshToken:
raise Exception("Refresh token is empty")
tokens = self.refresh_tokens(self.pluginRun.account[0].refreshToken)
except: # no account exists or expired refresh token
url = self.get_oauth_url()
code = self.present_url_to_user(url)
tokens = self.get_tokens_from_code(code)
# if not tokens: raise an exception or set pluginrun.state=FAILED and pluginRun.message=ERROR_MESSAGE
self.store_tokens(tokens)
def present_url_to_user(self, url):
if self.isTest:
return 'dummy_code'
# request user to visit url
self.pluginRun.oAuthUrl = url
self.pluginRun.state = RUN_USER_ACTION_NEEDED
self.pluginRun.update(self.client)
# WAIT HERE = BLOCK
while True:
sleep(self.SLEEP_INTERVAL)
self.pluginRun = self.client.get(self.pluginRun.id)
if self.pluginRun.state == RUN_USER_ACTION_COMPLETED:
return self.pluginRun.account[0].code
def store_tokens(self, tokens):
account = self.pluginRun.account[0]
account.accessToken = tokens['access_token']
account.refreshToken = tokens['refresh_token']
account.refreshToken = tokens['refresh_token'] if 'refresh_token' in tokens else None
account.update(self.client)
@abc.abstractmethod
def get_oauth_url(self):
raise NotImplemented()
@abc.abstractmethod
def get_tokens_from_code(self, code):
""" Gets access and refresh tokens from 3rd party service
and returns them in form:
{
'access_token': '...',
'refresh_token': '...'
}
"""
raise NotImplemented()
@abc.abstractmethod
def refresh_tokens(self):
""" Gets new tokens by using an existing refresh token
and returns them in form:
{
'access_token': '...',
'refresh_token': '...'
}
"""
# use self.pluginRun.account[0].refreshToken
raise NotImplemented()
```
%% Cell type:code id: tags:
``` python
# export
# hide
class ExampleOAuthAuthenticator(OAuthAuthenticator):
def get_oauth_url(self):
return "https://example.com/oauth"
def get_tokens_from_code(self, code):
return {
'access_token': 'dummy_access_token',
'refresh_token': 'dummy_refresh_token'
}
def refresh_tokens(self, refreshToken):
return {
'access_token': 'refreshed_dummy_access_token',
'refresh_token': 'refreshed_dummy_refresh_token'
}
```
......
......@@ -52,7 +52,7 @@ class OAuthAuthenticator(metaclass=abc.ABCMeta):
def store_tokens(self, tokens):
account = self.pluginRun.account[0]
account.accessToken = tokens['access_token']
account.refreshToken = tokens['refresh_token']
account.refreshToken = tokens['refresh_token'] if 'refresh_token' in tokens else None
account.update(self.client)
@abc.abstractmethod
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment