@keymastervn/redux-token-auth
Version:
Redux actions and reducers to integrate with Devise Token Auth
321 lines (292 loc) • 9.96 kB
text/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,
REGISTRATION_UPDATE_REQUEST_SENT,
REGISTRATION_UPDATE_REQUEST_SUCCEEDED,
REGISTRATION_UPDATE_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,
RegistrationUpdateRequestSentAction,
RegistrationUpdateRequestSucceededAction,
RegistrationUpdateRequestFailedAction,
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 registrationUpdateRequestSent = (): RegistrationUpdateRequestSentAction => ({
type: REGISTRATION_UPDATE_REQUEST_SENT
})
export const registrationUpdateRequestSucceeded = (
userAttributes: UserAttributes
): RegistrationUpdateRequestSucceededAction => ({
type: REGISTRATION_UPDATE_REQUEST_SUCCEEDED,
payload: {
userAttributes
}
})
export const registrationUpdateRequestFailed = (): RegistrationUpdateRequestFailedAction => ({
type: REGISTRATION_UPDATE_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(Storage, response.headers)
persistAuthHeadersInDeviceStorage(Storage, response.headers)
const userAttributesToSave = getUserAttributesFromResponse(
userAttributes,
response
)
dispatch(registrationRequestSucceeded(userAttributesToSave))
} catch (error) {
dispatch(registrationRequestFailed())
throw error
}
}
const updateUser = (userRegistrationDetails: UserRegistrationDetails) =>
async function(dispatch: Dispatch<{}>): Promise<void> {
dispatch(registrationUpdateRequestSent())
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: 'PUT',
url: authUrl,
data
})
setAuthHeaders(Storage, response.headers)
persistAuthHeadersInDeviceStorage(Storage, response.headers)
const userAttributesToSave = getUserAttributesFromResponse(
userAttributes,
response
)
dispatch(registrationUpdateRequestSucceeded(userAttributesToSave))
} catch (error) {
dispatch(registrationUpdateRequestFailed())
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(Storage, 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(Storage, 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,
updateUser,
verifyCredentials
}
}
export default generateAuthActions