accounts-frontend/src/services/api/authentication.js

164 lines
4.4 KiB
JavaScript
Raw Normal View History

2017-08-23 00:09:08 +05:30
// @flow
import type { UserResponse } from 'services/api/accounts';
import logger from 'services/logger';
import request, { InternalServerError } from 'services/request';
import { getInfo as getInfoEndpoint } from 'services/api/accounts';
2016-11-05 15:41:41 +05:30
const authentication = {
login({
2017-08-23 00:09:08 +05:30
login,
password,
totp,
rememberMe = false
2017-08-23 00:09:08 +05:30
}: {
login: string,
password?: string,
totp?: string,
rememberMe: bool
}) {
return request.post(
'/api/authentication/login',
2017-09-09 19:52:19 +05:30
{login, password, totp, rememberMe},
{token: null}
2017-09-09 19:52:19 +05:30
);
},
/**
* @param {object} options
2017-08-23 00:09:08 +05:30
* @param {string} [options.token] - an optional token to overwrite headers
* in middleware and disable token auto-refresh
*
* @return {Promise}
*/
logout(options: ?{
token: string
}) {
return request.post('/api/authentication/logout', {}, {
token: options && options.token
});
},
2016-07-28 10:33:30 +05:30
forgotPassword({
2017-08-23 00:09:08 +05:30
login,
captcha
}: {
login: string,
captcha: string
2016-07-28 10:33:30 +05:30
}) {
return request.post(
'/api/authentication/forgot-password',
{login, captcha},
{token: null}
2016-07-28 10:33:30 +05:30
);
},
recoverPassword({
2017-08-23 00:09:08 +05:30
key,
newPassword,
newRePassword
}: {
key: string,
newPassword: string,
newRePassword: string
2016-07-28 10:33:30 +05:30
}) {
return request.post(
'/api/authentication/recover-password',
{key, newPassword, newRePassword},
{token: null}
2016-07-28 10:33:30 +05:30
);
},
/**
* Resolves if token is valid
*
* @param {string} token
* @param {string} refreshToken
*
* @return {Promise} - resolves with options.token or with a new token
* if it was refreshed. As a side effect the response
* will have a `user` field with current user data
*
*/
async validateToken(token: string, refreshToken: ?string): Promise<{
2017-08-23 00:09:08 +05:30
token: string,
refreshToken: ?string,
user: UserResponse,
}> {
if (typeof token !== 'string') {
throw new Error('token must be a string');
}
// TODO: decode token to extract information about user id
let user: UserResponse;
try {
user = await getInfoEndpoint(0, { token });
} catch (resp) {
const { token } = await this.handleTokenError(resp, refreshToken);
user = await getInfoEndpoint(0, { token }); // TODO: replace with recursive call
}
2016-11-05 15:41:41 +05:30
return {
token,
refreshToken,
user,
};
},
handleTokenError(resp: Error | { message: string }, refreshToken: ?string): Promise<{
token: string,
}> {
if (resp instanceof InternalServerError) {
// delegate error recovering to the bsod middleware
return new Promise(() => {});
}
if (refreshToken) {
if ([
'Token expired',
'Incorrect token',
'You are requesting with an invalid credential.'
].includes(resp.message)) {
return authentication.requestToken(refreshToken);
}
2016-11-05 15:41:41 +05:30
logger.error('Unexpected error during token validation', {
resp
});
}
return Promise.reject(resp);
},
2016-08-10 00:47:49 +05:30
/**
* Request new access token using a refreshToken
*
* @param {string} refreshToken
*
* @return {Promise} - resolves to {token}
*/
2017-08-23 00:09:08 +05:30
requestToken(refreshToken: string): Promise<{token: string}> {
return request.post(
'/api/authentication/refresh-token',
{refresh_token: refreshToken}, // eslint-disable-line
{token: null}
)
.then((resp: {access_token: string}) => ({
token: resp.access_token
}))
.catch((resp) => {
const errors = resp.errors || {};
if (errors.refresh_token !== 'error.refresh_token_not_exist') {
logger.error('Failed refreshing token: unknown error', {
resp
});
}
return Promise.reject(resp);
});
}
};
2016-11-05 15:41:41 +05:30
export default authentication;