Repository: mozmeao/basket

Issue:
Reduce the TTL of the OAuth access token for FxA
See https://github.com/mozilla/fxa/issues/1810


Discussion:
@shane-tomlinson I'm looking at my code and I'm not seeing an opportunity to set a TTL for anything I'm doing. Is it an optional parameter for the authorization URL I send them to, or does it need to happen when exchanging the code I get when the user is redirected to me for the access token?

https://github.com/mozmeao/basket/blob/76773ce909f76a2a2bed5e8f4445c2f401e5ac73/basket/news/views.py#L199
If it's the latter we may need to add the option to the PyFxA library.
> If it's the latter we may need to add the option to the PyFxA library.

[It is the latter](https://github.com/mozilla/fxa/blob/6f64b72608db4095cc903026198e93a40549ea84/packages/fxa-auth-server/fxa-oauth-server/lib/routes/token.js#L102). Opened a [PyFxA PR](https://github.com/mozilla/PyFxA/pull/75) to help out.
@pmac what python version do you need for this, by the way? I note that CI is currently busted for PyFxA because its dependencies have been dropping support for python2 (as well they should) but not sure how to proceed with fixing that...
Thanks @shane-tomlinson, published in [PyFxA v0.7.3](https://pypi.org/project/PyFxA/0.7.3/).
> Thanks @shane-tomlinson, published in PyFxA v0.7.3.

Perfect. Thanks.
Thanks y'all! @rfk basket is running on Python 3.7 at present, so I think we should be good to go.

Resolving patch:
diff --git a/basket/news/views.py b/basket/news/views.py
--- a/basket/news/views.py
+++ b/basket/news/views.py
@@ -196,7 +196,7 @@ def fxa_callback(request):
 
     fxa_oauth, fxa_profile = get_fxa_clients()
     try:
-        access_token = fxa_oauth.trade_code(code)['access_token']
+        access_token = fxa_oauth.trade_code(code, ttl=settings.FXA_OAUTH_TOKEN_TTL)['access_token']
         user_profile = fxa_profile.get_profile(access_token)
     except Exception:
         statsd.incr('news.views.fxa_callback.error.fxa_comm')
diff --git a/basket/settings.py b/basket/settings.py
--- a/basket/settings.py
+++ b/basket/settings.py
@@ -377,6 +377,7 @@ def get_default_gateway_linux():
 FXA_OAUTH_SERVER_ENV = config('FXA_OAUTH_SERVER_ENV', default='stable')
 FXA_CLIENT_ID = config('FXA_CLIENT_ID', default='')
 FXA_CLIENT_SECRET = config('FXA_CLIENT_SECRET', default='')
+FXA_OAUTH_TOKEN_TTL = config('FXA_OAUTH_TOKEN_TTL', default=300, cast=int)  # 5 minutes
 
 FXA_EMAIL_PREFS_DOMAIN = config('FXA_EMAIL_PREFS_DOMAIN', default='www.mozilla.org')
 FXA_REGISTER_NEWSLETTER = config('FXA_REGISTER_NEWSLETTER', default='firefox-accounts-journey')


Test patch:
diff --git a/basket/news/tests/test_views.py b/basket/news/tests/test_views.py
--- a/basket/news/tests/test_views.py
+++ b/basket/news/tests/test_views.py
@@ -1279,7 +1279,7 @@ def test_existing_user(self):
         # no state
         resp = self.client.get('/fxa/callback/', {'code': 'thecode', 'state': 'thedude'})
         assert resp.status_code == 302
-        fxa_oauth_mock.trade_code.assert_called_with('thecode')
+        fxa_oauth_mock.trade_code.assert_called_with('thecode', ttl=settings.FXA_OAUTH_TOKEN_TTL)
         fxa_profile_mock.get_profile.assert_called_with('access-token')
         self.statsd.incr.assert_not_called()
         assert resp['location'] == 'https://www.mozilla.org/newsletter/existing/the-token/?fxa=1'
@@ -1302,7 +1302,7 @@ def test_new_user_with_locale(self):
         # no state
         resp = self.client.get('/fxa/callback/', {'code': 'thecode', 'state': 'thedude'})
         assert resp.status_code == 302
-        fxa_oauth_mock.trade_code.assert_called_with('thecode')
+        fxa_oauth_mock.trade_code.assert_called_with('thecode', ttl=settings.FXA_OAUTH_TOKEN_TTL)
         fxa_profile_mock.get_profile.assert_called_with('access-token')
         self.statsd.incr.assert_not_called()
         assert resp['location'] == 'https://www.mozilla.org/newsletter/existing/the-new-token/?fxa=1'
@@ -1332,7 +1332,7 @@ def test_new_user_without_locale(self):
         # no state
         resp = self.client.get('/fxa/callback/', {'code': 'thecode', 'state': 'thedude'})
         assert resp.status_code == 302
-        fxa_oauth_mock.trade_code.assert_called_with('thecode')
+        fxa_oauth_mock.trade_code.assert_called_with('thecode', ttl=settings.FXA_OAUTH_TOKEN_TTL)
         fxa_profile_mock.get_profile.assert_called_with('access-token')
         self.statsd.incr.assert_not_called()
         assert resp['location'] == 'https://www.mozilla.org/newsletter/existing/the-new-token/?fxa=1'