redux-token-auth/src/actions.ts

260 lines
7.7 KiB
TypeScript

import axios from 'axios'
import {
Dispatch,
Store,
} from 'redux'
import {
AuthResponse,
DeviceStorage,
VerificationParams,
UserAttributes,
UserRegistrationDetails,
UserSignInCredentials,
UserSignOutCredentials,
ActionsExport,
REGISTRATION_REQUEST_SENT,
REGISTRATION_REQUEST_SUCCEEDED,
REGISTRATION_REQUEST_FAILED,
VERIFY_TOKEN_REQUEST_SENT,
VERIFY_TOKEN_REQUEST_SUCCEEDED,
VERIFY_TOKEN_REQUEST_FAILED,
SIGNIN_REQUEST_SENT,
SIGNIN_REQUEST_SUCCEEDED,
SIGNIN_REQUEST_FAILED,
SIGNOUT_REQUEST_SENT,
SIGNOUT_REQUEST_SUCCEEDED,
SIGNOUT_REQUEST_FAILED,
SET_HAS_VERIFICATION_BEEN_ATTEMPTED,
RegistrationRequestSentAction,
RegistrationRequestSucceededAction,
RegistrationRequestFailedAction,
VerifyTokenRequestSentAction,
VerifyTokenRequestSucceededAction,
VerifyTokenRequestFailedAction,
SignInRequestSentAction,
SignInRequestSucceededAction,
SignInRequestFailedAction,
SignOutRequestSentAction,
SignOutRequestSucceededAction,
SignOutRequestFailedAction,
SetHasVerificationBeenAttemptedAction,
} from './types'
import AsyncLocalStorage from './AsyncLocalStorage'
import {
deleteAuthHeaders,
deleteAuthHeadersFromDeviceStorage,
getUserAttributesFromResponse,
persistAuthHeadersInDeviceStorage,
setAuthHeaders,
} from './services/auth'
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Pure Redux actions:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
export const registrationRequestSent = (): RegistrationRequestSentAction => ({
type: REGISTRATION_REQUEST_SENT,
})
export const registrationRequestSucceeded = (userAttributes: UserAttributes): RegistrationRequestSucceededAction => ({
type: REGISTRATION_REQUEST_SUCCEEDED,
payload: {
userAttributes,
},
})
export const registrationRequestFailed = (): RegistrationRequestFailedAction => ({
type: REGISTRATION_REQUEST_FAILED,
})
export const verifyTokenRequestSent = (): VerifyTokenRequestSentAction => ({
type: VERIFY_TOKEN_REQUEST_SENT,
})
export const verifyTokenRequestSucceeded = (userAttributes: UserAttributes): VerifyTokenRequestSucceededAction => ({
type: VERIFY_TOKEN_REQUEST_SUCCEEDED,
payload: {
userAttributes,
},
})
export const verifyTokenRequestFailed = (): VerifyTokenRequestFailedAction => ({
type: VERIFY_TOKEN_REQUEST_FAILED,
})
export const signInRequestSent = (): SignInRequestSentAction => ({
type: SIGNIN_REQUEST_SENT,
})
export const signInRequestSucceeded = (userAttributes: UserAttributes): SignInRequestSucceededAction => ({
type: SIGNIN_REQUEST_SUCCEEDED,
payload: {
userAttributes,
},
})
export const signInRequestFailed = (): SignInRequestFailedAction => ({
type: SIGNIN_REQUEST_FAILED,
})
export const signOutRequestSent = (): SignOutRequestSentAction => ({
type: SIGNOUT_REQUEST_SENT,
})
export const signOutRequestSucceeded = (): SignOutRequestSucceededAction => ({
type: SIGNOUT_REQUEST_SUCCEEDED,
})
export const signOutRequestFailed = (): SignOutRequestFailedAction => ({
type: SIGNOUT_REQUEST_FAILED,
})
export const setHasVerificationBeenAttempted = (
hasVerificationBeenAttempted: boolean
): SetHasVerificationBeenAttemptedAction => ({
type: SET_HAS_VERIFICATION_BEEN_ATTEMPTED,
payload: {
hasVerificationBeenAttempted,
},
})
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Async Redux Thunk actions:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const generateAuthActions = (config: { [key: string]: any }): ActionsExport => {
const {
authUrl,
storage,
userAttributes,
userRegistrationAttributes,
} = config
const Storage: DeviceStorage = Boolean(storage.flushGetRequests) ? storage : AsyncLocalStorage
const registerUser = (
userRegistrationDetails: UserRegistrationDetails,
) => async function (dispatch: Dispatch<{}>): Promise<void> {
dispatch(registrationRequestSent())
const {
email,
password,
passwordConfirmation,
} = userRegistrationDetails
const data = {
email,
password,
password_confirmation: passwordConfirmation,
}
Object.keys(userRegistrationAttributes).forEach((key: string) => {
const backendKey = userRegistrationAttributes[key]
data[backendKey] = userRegistrationDetails[key]
})
try {
const response: AuthResponse = await axios({
method: 'POST',
url: authUrl,
data,
})
setAuthHeaders(response.headers)
persistAuthHeadersInDeviceStorage(Storage, response.headers)
const userAttributesToSave = getUserAttributesFromResponse(userAttributes, response)
dispatch(registrationRequestSucceeded(userAttributesToSave))
} catch (error) {
dispatch(registrationRequestFailed())
throw error
}
}
const verifyToken = (
verificationParams: VerificationParams,
) => async function (dispatch: Dispatch<{}>): Promise<void> {
dispatch(verifyTokenRequestSent())
try {
const response = await axios({
method: 'GET',
url: `${authUrl}/validate_token`,
params: verificationParams,
})
setAuthHeaders(response.headers)
persistAuthHeadersInDeviceStorage(Storage, response.headers)
const userAttributesToSave = getUserAttributesFromResponse(userAttributes, response)
dispatch(verifyTokenRequestSucceeded(userAttributesToSave))
} catch (error) {
dispatch(verifyTokenRequestFailed())
}
}
const signInUser = (
userSignInCredentials: UserSignInCredentials,
) => async function (dispatch: Dispatch<{}>): Promise<void> {
dispatch(signInRequestSent())
const {
email,
password,
} = userSignInCredentials
try {
const response = await axios({
method: 'POST',
url: `${authUrl}/sign_in`,
data: {
email,
password,
},
})
setAuthHeaders(response.headers)
persistAuthHeadersInDeviceStorage(Storage, response.headers)
const userAttributesToSave = getUserAttributesFromResponse(userAttributes, response)
dispatch(signInRequestSucceeded(userAttributesToSave))
} catch (error) {
dispatch(signInRequestFailed())
throw error
}
}
const signOutUser = () => async function (dispatch: Dispatch<{}>): Promise<void> {
const userSignOutCredentials: UserSignOutCredentials = {
'access-token': await Storage.getItem('access-token') as string,
client: await Storage.getItem('client') as string,
uid: await Storage.getItem('uid') as string,
}
dispatch(signOutRequestSent())
try {
await axios({
method: 'DELETE',
url: `${authUrl}/sign_out`,
data: userSignOutCredentials,
})
deleteAuthHeaders()
deleteAuthHeadersFromDeviceStorage(Storage)
dispatch(signOutRequestSucceeded())
} catch (error) {
dispatch(signOutRequestFailed())
throw error
}
}
const verifyCredentials = async (store: Store<{}>): Promise<void> => {
if (await Storage.getItem('access-token')) {
const verificationParams: VerificationParams = {
'access-token': await Storage.getItem('access-token') as string,
client: await Storage.getItem('client') as string,
uid: await Storage.getItem('uid') as string,
}
store.dispatch<any>(verifyToken(verificationParams))
} else {
store.dispatch(setHasVerificationBeenAttempted(true))
}
}
return {
registerUser,
verifyToken,
signInUser,
signOutUser,
verifyCredentials,
}
}
export default generateAuthActions