diff --git a/api/config/api_urls.py b/api/config/api_urls.py index 13205fe3de7bf93b9c46add6a71970da6ac68d4f..a41c7bc0f3eb1b524f15b88f166b93141af2b1d9 100644 --- a/api/config/api_urls.py +++ b/api/config/api_urls.py @@ -46,9 +46,8 @@ v1_patterns += [ include( ('funkwhale_api.users.api_urls', 'users'), namespace='users')), - url(r'^token/', - jwt_views.obtain_jwt_token), - url(r'^token/refresh/', jwt_views.refresh_jwt_token), + url(r'^token/$', jwt_views.obtain_jwt_token, name='token'), + url(r'^token/refresh/$', jwt_views.refresh_jwt_token, name='token_refresh'), ] urlpatterns = [ diff --git a/api/tests/users/test_views.py b/api/tests/users/test_views.py index 42be77b7c18a2cd4b25829b1b567d044b0d9c6b9..5dbb24ac67eae64b0f484beb95a1523d1b7a0333 100644 --- a/api/tests/users/test_views.py +++ b/api/tests/users/test_views.py @@ -62,3 +62,38 @@ def test_can_fetch_data_from_api(client, factories): assert payload['name'] == user.name assert payload['permissions']['import.launch']['status'] assert payload['permissions']['settings.change']['status'] + + +def test_can_get_token_via_api(client, factories): + user = factories['users.User']() + url = reverse('api:v1:token') + payload = { + 'username': user.username, + 'password': 'test' + } + + response = client.post(url, payload) + assert response.status_code == 200 + assert '"token":' in response.content.decode('utf-8') + + +def test_can_refresh_token_via_api(client, factories): + # first, we get a token + user = factories['users.User']() + url = reverse('api:v1:token') + payload = { + 'username': user.username, + 'password': 'test' + } + + response = client.post(url, payload) + assert response.status_code == 200 + + token = json.loads(response.content.decode('utf-8'))['token'] + url = reverse('api:v1:token_refresh') + response = client.post(url,{'token': token}) + + assert response.status_code == 200 + assert '"token":' in response.content.decode('utf-8') + # a different token should be returned + assert token in response.content.decode('utf-8') diff --git a/front/package.json b/front/package.json index 3eb5201b29d1a6cc76212a290459c471b23a6677..9af43238767258ddb082b17659b6b9d278dd7952 100644 --- a/front/package.json +++ b/front/package.json @@ -16,6 +16,7 @@ "dependencies": { "dateformat": "^2.0.0", "js-logger": "^1.3.0", + "jwt-decode": "^2.2.0", "lodash": "^4.17.4", "semantic-ui-css": "^2.2.10", "vue": "^2.3.3", diff --git a/front/src/store/auth.js b/front/src/store/auth.js index eea508df9518b66c050750d8d654748a7aee9df8..815b0f70893da6fb0543b72c420dfcd9a02effc6 100644 --- a/front/src/store/auth.js +++ b/front/src/store/auth.js @@ -1,9 +1,11 @@ import Vue from 'vue' +import jwtDecode from 'jwt-decode' import config from '@/config' import logger from '@/logging' import router from '@/router' const LOGIN_URL = config.API_URL + 'token/' +const REFRESH_TOKEN_URL = config.API_URL + 'token/refresh/' const USER_PROFILE_URL = config.API_URL + 'users/users/me/' export default { @@ -13,7 +15,8 @@ export default { username: '', availablePermissions: {}, profile: null, - token: '' + token: '', + tokenData: {} }, getters: { header: state => { @@ -32,6 +35,7 @@ export default { }, token: (state, value) => { state.token = value + state.tokenData = jwtDecode(value) }, permission: (state, {key, status}) => { state.availablePermissions[key] = status @@ -70,6 +74,7 @@ export default { commit('token', jwt) logger.default.info('Logged back in as ' + username) dispatch('fetchProfile') + dispatch('refreshToken') } else { logger.default.info('Anonymous user') commit('authenticated', false) @@ -90,6 +95,15 @@ export default { }, (response) => { logger.default.info('Error while fetching user profile') }) + }, + refreshToken ({commit, dispatch, state}) { + let resource = Vue.resource(REFRESH_TOKEN_URL) + return resource.save({}, {token: state.token}).then(response => { + logger.default.info('Refreshed auth token') + commit('token', response.data.token) + }, response => { + logger.default.error('Error while refreshing token', response.data) + }) } } }