I have done jwt authorization and registration. But when checking whether the user is authorized, he issues 401 Unauthorized sent a request to receive a refresh token via axios
Here is the authorization verification action:
export const checkAuth = () => {
try {
return async dispatch => {
const response = await axios.get(`http://localhost:5000/api/refresh`, {withCredentials: true})
//console.log(response)
dispatch({
type: SET_USER,
payload: response.data
})
}
} catch (e) {
console.log(e.response?.data?.message);
}
}
here is the reducer:
import {LOGOUT, SET_USER} from "../types";
const initialState = {
currentUser: {},
isAuth: false
}
export const authReducer = (state = initialState, action) => {
switch (action.type) {
case SET_USER:
localStorage.setItem('token', action.payload.accessToken);
return {
...state,
currentUser: action.payload,
isAuth: true
}
case LOGOUT:
localStorage.removeItem('token')
return {
...state,
currentUser: {},
isAuth: false
}
default:
return state
}
}
export const logout = () => ({type: LOGOUT})
Here is the app component:
import './App.css';
import {Route, Routes} from "react-router-dom";
import LoginForm from "./component/LoginForm";
import {useDispatch, useSelector} from "react-redux";
import RegisterForm from "./component/RegisterForm";
import {useEffect} from "react";
import {checkAuth} from "./redux/action";
function App() {
const users = useSelector(state => {
const {authReducer} = state
return authReducer
})
const dispatch = useDispatch()
//console.log(users)
useEffect(() => {
checkAuth() // here I did dispatch()
}, [])
if (!users.isAuth) {
return (<div>
<Routes>
<Route path="/registration" element={<RegisterForm/>}/>
<Route path="/login" element={<LoginForm/>}/>
</Routes>
</div>)
}
console.log(users.currentUser)
return (
<div className="App">
{users.isAuth ? users.currentUser.rows.map(data => <div key={data.id}>{data.email}</div>) : 'log in'}
</div>
);
}
export default App;
Here are the axios settings, but I tried using fetch() and the result is the same (401)
import axios from "axios";
export const API_URL = `http://localhost:5000/api`
const $api = axios.create({
withCredentials: true,
baseURL: API_URL
})
$api.interceptors.request.use((config) => {
config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`
return config;
})
$api.interceptors.response.use((config) => {
return config;
},async (error) => {
const originalRequest = error.config;
if (error.response.status == 401 && error.config && !error.config._isRetry) {
originalRequest._isRetry = true;
try {
const response = await axios.get(`${API_URL}/refresh`, {withCredentials: true})
localStorage.setItem('token', response.data.accessToken);
return $api.request(originalRequest);
} catch (e) {
console.log('NOT AUTHORIZED')
}
}
throw error;
})
export default $api;
I installed cars on the server and call it like this
app.use(cors()) // Use this after the variable declaration / I tried such settings, it didn't help {credentials: true, origin: 'http://localhost:3000'}
For some reason, a 401 error pops up, although everything works in postman!
Why don't I know anymore!???
Related
On my website switching between pages is completely fine and works (it doesnt refresh or load due to redux) but the moment the page is refreshed or i manually enter a link to access, it logs me out. Also it just started happening now, yesterday when i was working on some other things in code, it never logged me out when I manually with links/urls navigated thru website or refreshing but now for some reason it doesnt work and I'm 99% sure I havent touched any auth part of the code...
This is my code:
authApiSlice:
import { apiSlice } from "../../app/api/apiSlice";
import { logOut, setCredentials } from "./authSlice";
export const authApiSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
login: builder.mutation({
query: (credentials) => ({
url: "/auth",
method: "POST",
body: { ...credentials },
}),
}),
sendLogout: builder.mutation({
query: () => ({
url: "/auth/logout",
method: "POST",
}),
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled;
console.log(data);
dispatch(logOut());
setTimeout(() => {
dispatch(apiSlice.util.resetApiState());
}, 1000);
} catch (err) {
console.log(err);
}
},
}),
refresh: builder.mutation({
query: () => ({
url: "/auth/refresh",
method: "GET",
}),
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled;
console.log(data);
const { accessToken } = data;
dispatch(setCredentials({ accessToken }));
} catch (err) {
console.log(err);
}
},
}),
}),
});
export const { useLoginMutation, useSendLogoutMutation, useRefreshMutation } =
authApiSlice;
authSlice:
import { createSlice } from "#reduxjs/toolkit";
const authSlice = createSlice({
name: "auth",
initialState: { token: null },
reducers: {
setCredentials: (state, action) => {
const { accessToken } = action.payload;
state.token = accessToken;
},
logOut: (state, action) => {
state.token = null;
},
},
});
export const { setCredentials, logOut } = authSlice.actions;
export default authSlice.reducer;
export const selectCurrentToken = (state) => state.auth.token;
import { Outlet, Link } from "react-router-dom";
import { useEffect, useRef, useState } from "react";
import { useRefreshMutation } from "./authApiSlice";
import usePersist from "../../hooks/usePersist";
import { useSelector } from "react-redux";
import { selectCurrentToken } from "./authSlice";
const PersistLogin = () => {
const [persist] = usePersist();
const token = useSelector(selectCurrentToken);
const effectRan = useRef(false);
const [trueSuccess, setTrueSuccess] = useState(false);
const [refresh, { isUninitialized, isLoading, isSuccess, isError, error }] =
useRefreshMutation();
useEffect(() => {
if (effectRan.current === true || process.env.NODE_ENV !== "development") {
// React 18 Strict Mode
const verifyRefreshToken = async () => {
console.log("verifying refresh token");
try {
//const response =
await refresh();
//const { accessToken } = response.data
setTrueSuccess(true);
} catch (err) {
console.error(err);
}
};
if (!token && persist) verifyRefreshToken();
}
return () => (effectRan.current = true);
// eslint-disable-next-line
}, []);
let content;
if (!persist) {
// persist: no
console.log("no persist");
content = <Outlet />;
} else if (isLoading) {
//persist: yes, token: no
console.log("loading");
} else if (isError) {
//persist: yes, token: no
console.log("error");
content = (
<p className="errmsg">
{`${error?.data?.message} - `}
<Link to="/login">Please login again</Link>.
</p>
);
} else if (isSuccess && trueSuccess) {
//persist: yes, token: yes
console.log("success");
content = <Outlet />;
} else if (token && isUninitialized) {
//persist: yes, token: yes
console.log("token and uninit");
console.log(isUninitialized);
content = <Outlet />;
}
return content;
};
export default PersistLogin;
RequireAuth
import { useLocation, Navigate, Outlet } from "react-router-dom";
import useAuth from "../../hooks/useAuth";
const RequireAuth = ({ allowedRoles }) => {
const location = useLocation();
const { roles } = useAuth();
const content = roles.some((role) => allowedRoles.includes(role)) ? (
<Outlet />
) : (
<Navigate to="/prijava" state={{ from: location }} replace />
);
return content;
};
export default RequireAuth;
It just stopped worked for some reason, it shouldnt log me out when I refresh.
I am trying to get the token from the api's provided by spotify everything here works as expected except one. When my reducer updates my authentication state it doesn't perform the re-render in my component where ever auth token is used. It still showing undefined after updating the store but when i refresh the login url it shows changes that were previously made.
here is my login.jsx
import { generateAuthorizeUrl, extractUrlParams } from "../utils";
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { scopes } from "../spotify";
import { signIn } from "../actions";
const Login = (props) => {
const { refreshToken, loading, error } = useSelector((state) => state.auth);
console.log(refreshToken, loading, error);
const dispatch = useDispatch();
const onClickHandler = function (e) {
e.preventDefault();
var a = document.createElement("a");
a.href = generateAuthorizeUrl()(scopes);
a.click();
};
useEffect(() => {
if (window.location.search.includes("code=") && !refreshToken) {
var { code, state } = extractUrlParams();
dispatch(signIn(code, state));
}
}, [dispatch, refreshToken]);
return (
<div>
{props.refreshToken}
<button onClick={onClickHandler}>login with spotify</button>
</div>
);
};
export default Login;
here is my authAction to perform when spotify redirect me with code and state parameter in url
import axios from "axios";
import {
USER_SIGNIN_FAILURE,
USER_SIGNIN_REQUEST,
USER_SIGNIN_SUCCESS,
} from "../contants/AuthConstants";
import { Base64, getItem } from "../utils";
// DISPATCH DATA FOR MAKING REQUEST STATE
const signInRequest = () => ({ type: USER_SIGNIN_REQUEST });
// DISPATCH DATA FOR SUCCESS AND FAILURE REQUEST
const signInResponse = (error = false, data) => ({
type: error ? USER_SIGNIN_FAILURE : USER_SIGNIN_SUCCESS,
payload: data,
});
// SIGN IN ACTION TO BE DISPATCHED TO REDUCER FOR LOGIN STUFF
export const signIn = (code, state) => async (dispatch, getState) => {
dispatch(signInRequest());
let _state = getItem(process.env.REACT_APP_STATE_KEY);
// CHECK IF STATE IS NULL OR PROVIDED STATE DOES NOT MATCHES STATE STORED IN LOCALSTORAGE
if (!state || state !== _state) {
// IF TRUE OUR AUTHORAIZATION FAILS
dispatch(signInResponse(true, "state mismatched, Authorization failed"));
} else {
// ELSE MAKE REQUEST TO TOKEN URI FOR ACCEPTION TOKEN
await axios({
url: process.env.REACT_APP_TOKEN_URI,
method: "POST",
data: new URLSearchParams({
code: code,
redirect_uri: process.env.REACT_APP_REDIRECT_URI,
grant_type: "authorization_code",
}).toString(),
headers: {
Authorization: `Basic ${Base64.encode(
`${process.env.REACT_APP_CLIENT_ID}:${process.env.REACT_APP_CLIENT_SECRET}`
)}`,
"Content-Type": "application/x-www-form-urlencoded",
},
})
.then((res) => {
dispatch(signInResponse(false, res.data));
})
.catch((error) => dispatch(signInResponse(true, error.message)));
}
};
here is the authReducer
import {
USER_SIGNIN_FAILURE,
USER_SIGNIN_REQUEST,
USER_SIGNIN_SUCCESS,
} from "../contants/AuthConstants";
import { setItem } from "../utils";
const AuthReducer = (state = { loading: false, error: "" }, action) => {
switch (action.type) {
case USER_SIGNIN_REQUEST:
return { ...state, loading: true };
case USER_SIGNIN_SUCCESS:
let auth = {
refreshToken: action.payload.refresh_token,
accessToken: action.payload.access_token,
expiresIn: new Date().getTime() + 3540 * 1000,
tokenType: action.payload.token_type,
};
setItem(process.env.REACT_APP_TOKEN_KEY)(JSON.stringify(auth));
return {
...state,
loading: false,
auth: auth,
error: null,
};
case USER_SIGNIN_FAILURE:
return { ...state, loading: false, error: action.payload, auth: {} };
default:
return state;
}
};
export { AuthReducer };
here is store.js
import { applyMiddleware, combineReducers, compose, createStore } from "redux";
import thunk from "redux-thunk";
import { AuthReducer } from "../reducers/AuthReducers";
import { getItem } from "../utils";
const initialState = {
auth: getItem(process.env.REACT_APP_TOKEN_KEY)
? JSON.parse(getItem(process.env.REACT_APP_TOKEN_KEY))
: {},
};
const rootReducer = combineReducers({
auth: AuthReducer,
});
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
initialState,
composeEnhancer(applyMiddleware(thunk))
);
export default store;
Here is Login Component parent Container
import { BrowserRouter, Routes, Route } from "react-router-dom";
import styled from "styled-components";
import Privateroute from "./route/PrivateRoute";
import { Home, Login } from "./screens";
function App() {
return (
<BrowserRouter>
<AppContainer>
<Routes>
<Route path="/auth/login" element={<Login />} />
<Route
path="/"
element={
<Privateroute>
<Home />
</Privateroute>
}
></Route>
</Routes>
</AppContainer>
</BrowserRouter>
);
}
const AppContainer = styled.div``;
export default App;
and last here is my private route component
import React from "react";
import { useSelector } from "react-redux";
import { Navigate } from "react-router-dom";
const Privateroute = (props) => {
const token = useSelector((state) => state.auth.refreshToken);
return token ? props.children : <Navigate to="/auth/login" />;
};
export default Privateroute;
You need to wrap your code with <Provider store={store}></Provider>
So I have a mobile app in react native for which I am trying to create the auth flow properly.I had this first as a web app and then now trying to do the same as a mobile app. I am using redux for state management.
Here is the flow: Once the user logs in or registers, I send the data to the backend using axios. The backend generates a user token. I would like to create a system where I can fetch the token when a user logs in and store that with AsyncStorage so that I can directly log the user in when he or she tries to open the app again.
Here is the code, more than happy to answer any questions, this was done through a react tutorial really:
LoginScreen.js
const Login = ( { navigation }) => {
const [email, setEmail] = useState();
const [password, setPassword] = useState();
const [message, setMessage] = useState(null)
// Errors
const [EmailMessage, setEmailMessage] = useState(null);
const [PasswordMessage, setPasswordMessage] = useState(null);
const dispatch = useDispatch();
const userLogin = useSelector((state) => state.userLogin);
const { loading, error, userInfo } = userLogin
useEffect(() => {
if (userInfo) {
navigation.navigate('MainTabs', { screen: 'Home'});
}
}, [navigation, userInfo]);
const submitHandler = (e) => {
e.preventDefault();
if (!email) {
alert('Please fill in the email');
return
};
if (!password) {
alert('Please fill in the password');
return
}
dispatch(login(email, password));
};
The return part is the frontend code so left that out for the sake of brevity
Now the redux part:
userActions.js
import axios from "axios";
import { USER_LOGIN_FAIL, USER_LOGIN_REQUEST, USER_LOGIN_SUCCESS, USER_LOGOUT, USER_REGISTER_FAIL, USER_REGISTER_SUCCESS, USER_REGISTER_REQUEST } from "../constants/userConstants"
import AsyncStorage from '#react-native-async-storage/async-storage';
export const login = (email, password) => async(dispatch) => {
try {
dispatch({ type: USER_LOGIN_REQUEST });
const config = {
headers: {
"Content-type": "application/json"
}
}
const {data} = await axios.post("api/url", {email, password}, config)
dispatch({type: USER_LOGIN_SUCCESS, payload:data});
await AsyncStorage.setItem("userInfo", JSON.stringify(data))
} catch (error) {
dispatch({
type: USER_LOGIN_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
})
console.log("This login attempt is unsuccessful");
}
}
export const logout = () => async (dispatch) => {
await AsyncStorage.removeItem("userInfo")
dispatch({ type: USER_LOGOUT });
};
export const register = (full_name, email, password, social) => async(dispatch) => {
try {
dispatch({type: USER_REGISTER_REQUEST});
const config = {
headers: {
"Content-type": "application/json"
}
};
const {data} = await axios.post("api/url", {full_name, email, password, social}, config);
dispatch({ type: USER_REGISTER_SUCCESS, payload: data});
dispatch({ type: USER_LOGIN_SUCCESS, payload: data});
await AsyncStorage.setItem("userInfo", JSON.stringify(data))
} catch (error) {
dispatch({type: USER_REGISTER_FAIL, payload:
error.response && error.response.data.message
? error.response.data.message
: error.message
})
}}
userReducers.js
import { USER_LOGIN_REQUEST, USER_REGISTER_FAIL, USER_REGISTER_REQUEST, USER_REGISTER_SUCCESS } from "../constants/userConstants";
import { USER_LOGIN_SUCCESS, USER_LOGIN_FAIL, USER_LOGOUT } from "../constants/userConstants";
export const userLoginReducer = (state = {}, action) => {
switch (action.type) {
case USER_LOGIN_REQUEST:
return {loading: true}
case USER_LOGIN_SUCCESS:
return {loading: false, userInfo: action.payload}
case USER_LOGIN_FAIL:
return {loading: false, error:action.payload}
case USER_LOGOUT:
return {}
default:
return state;
}
}
export const userRegisterReducer = (state = {}, action) => {
switch (action.type) {
case USER_REGISTER_REQUEST:
return {loading:true}
case USER_REGISTER_SUCCESS:
return {loading:false, userInfo: action.payload}
case USER_REGISTER_FAIL:
return {loading:false, error: action.payload}
default:
return state;
}
}
store.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from "redux-thunk";
import { userLoginReducer, userRegisterReducer } from './src/redux/reducers/userReducers';
import AsyncStorage from '#react-native-async-storage/async-storage';
const reducer = combineReducers({
//contains reducers
userLogin: userLoginReducer,
userRegister: userRegisterReducer
});
const middleware = [thunk];
const getData = async () => {
try {
const value = await AsyncStorage.getItem("userInfo")
return value != null ? JSON.parse(value) : null;
} catch(e) {
console.log("this attempt is not successful");
}
}
const userInfoFromStorage = getData() || null;
alert(JSON.stringify(userInfoFromStorage))
const initialState = {
userLogin: {userInfo: userInfoFromStorage}
};
const store = createStore(
reducer,
initialState,
applyMiddleware(...middleware)
);
export default store
I would appreciate any help here as I am not able to resolve how to solve this is this is a promise issue on fetch or something more general than that. I have a token generated in the backend once I register a user. I would really appreciate if anyone knows of the best way on how to fetch and save that token and log the user in if the user had already logged in
First, create a file with the name authProvider.ts. This will hold objects, with key as isAuthenticated and async getAuthToken() with callback function as property.
const authProvider: any = {
isAuthenticated: false,
authToken: null,
async getAuthToken(callback: VoidFunction) {
await GetSessionData('Access-token').then(
res => {
if (res) {
authProvider.isAuthenticated = true;
authProvider.authToken = res;
callback();
} else {
authProvider.isAuthenticated = false;
authProvider.authToken = res;
callback();
}
}
);
}
};
export { authProvider };
export const GetSessionData = async (key: string) => {
return await AsyncStorage.getItem(
key,
(err, value) => {
if (err) {
console.log(err);
} else {
return value;
}
}
);
}
In app.tsx
In App component we will call the above authProvider to get the token from Async storage using await. Once done it will execute the below callback function logic.
const App = () => {
const [isLoading, setLoading] = useState<boolean>(true);
useEffect(() => {
authProvider.getAuthToken(() => {
if (authProvider.isAuthenticated) {
store.dispatch(isAuthenticatedUser(true));
setLoading(false);
} else {
store.dispatch(isAuthenticatedUser(false));
setLoading(false);
// *** redirect to login page logic ***.
}
});
}, []);
return (
<>
<Provider store={store}>
{
!isLoading ?
<Dashboard /> :
<AppLoader />
}
</Provider>
</>
);
}
I'm working on a react project. I have my own API to fetch information. I'm using the useEffect hook to fetch profile information from API. My problem is when page mounts for the first time i can fetch the data with no problem but if i refresh the page it doesn't work at all. I know i have to give a second parameter to useEffect. I tried to put profile as the second argument even dispatched the getCurrentProfile function but when i do that it constantly fires off fetch request. I would be glad if anyone can help me with that. Thanks.
Here is my Profile component:
export const Profile = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(getCurrentProfile());
}, [])
const profileReducer = useSelector((state) => state.profile);
const authReducer = useSelector((state) => state.auth);
const { profile, error, loading } = profileReducer;
const { user } = authReducer;
console.log("loading", loading)
console.log("profile", profile)
return loading && profile === null ? (
<div >
<Spinner />
</div>
) :
Here is my Profile action:
export const getCurrentProfile = () => async dispatch => {
try {
const res = await axios.get("/api/profile/me");
console.log(res);
dispatch({
type: "GET_PROFILE",
payload: res.data.data
})
} catch (err) {
dispatch({
type: "PROFILE_ERROR",
payload: { msg: err.response.statusText, status: err.response.status }
})
}
}
Here is my profile reducer:
export default (state = initialState, action) => {
const { type, payload } = action;
switch (type) {
case "GET_PROFILE":
return {
...state,
profile: payload,
loading: false
}
case "PROFILE_ERROR":
return {
...state,
error: payload,
profile: null
}
case "CLEAR_PROFILE":
return {
...state,
profile: null,
loading: false
}
default:
return state;
}
}
You might want to try adding conditional logic within the useEffect so you only trigger the dispatch if you don't already have a profile.
import "./styles.css";
import { useDispatch, useSelector } from "react-redux";
import { useEffect, useCallback } from "react";
import { getCurrentProfile } from "./action";
export const Profile = () => {
const dispatch = useDispatch();
const profileReducer = useSelector((state) => state.profile);
const authReducer = useSelector((state) => state.auth);
const { profile, error, loading } = profileReducer;
// read more about this here: https://stackoverflow.com/questions/58624200/react-hook-useeffect-has-a-missing-dependency-dispatch
const stableDispatch = useCallback(dispatch, []);
useEffect(() => {
if (!profile) {
stableDispatch(getCurrentProfile());
}
}, [profile, stableDispatch]);
const { user } = authReducer;
console.log("loading", loading);
console.log("profile", profile);
return loading && profile === null ? <div>Spinner</div> : "Actual Profile";
};
export default Profile;
Also, it doesn't seem like you're currently doing anything with the loading piece of state–at least from what you've shared here. You might want to dispatch an action indicating that you're loading before you start the fetch and then it will be set to false when you get the response.
Check out this codesandbox for reference: https://codesandbox.io/s/focused-kilby-gd2nr?file=/src/App.js
Reducers:
const initialState = {
profile: null,
loading: false
};
export const profile = (state = initialState, action) => {
const { type, payload } = action;
switch (type) {
case "LOADING_PROFILE":
return {
...state,
loading: true
};
case "GET_PROFILE":
return {
...state,
profile: payload,
loading: false
};
case "PROFILE_ERROR":
return {
...state,
error: payload,
profile: null
};
case "CLEAR_PROFILE":
return {
...state,
profile: null,
loading: false
};
default:
return state;
}
};
export const auth = (state = {}, action) => {
return state;
};
Action Creator:
import axios from "axios";
export const getCurrentProfile = () => async (dispatch) => {
try {
dispatch({ type: "LOADING_PROFILE" });
const res = await axios.get("https://jsonplaceholder.typicode.com/users/1");
console.log(res);
dispatch({
type: "GET_PROFILE",
payload: res.data.data
});
} catch (err) {
dispatch({
type: "PROFILE_ERROR",
payload: { msg: err.response.statusText, status: err.response.status }
});
}
};
index.js
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore, combineReducers, applyMiddleware } from "redux";
import { profile, auth } from "./reducers";
import App from "./App";
import thunk from "redux-thunk";
const store = createStore(
combineReducers({
profile,
auth
}),
applyMiddleware(thunk)
);
const rootElement = document.getElementById("root");
ReactDOM.render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>,
rootElement
);
Well i solved it by dispatching 'getCurrentProfile' not 'getCurrentProfile()' turns out using it like a function causes continuously firing off.
const profileReducer = useSelector((state) => state.profile);
const authReducer = useSelector((state) => state.auth);
const { profile, error, loading } = profileReducer;
const dispatch = useDispatch();
useEffect(() => {
if (!profile) {
console.log("It worked")
dispatch(getCurrentProfile());
}
}, [dispatch(getCurrentProfile)])
i have get token from login with react redux, if i am try to authorized it with this token. the error is show Axios request failed: TypeError: Cannot read property 'token' of undefined i want to authorized it with token. the token is stored in localstorage but it can't authorized it when i am using (Token ${props.token} if i am trying this way (Token 5302f4340a76cd80a855286c6d9e0e48d2f519cb} then my AritcleList.js is Authorized it
here is the react-redux authentication
authAction.js
import axios from 'axios';
import * as actionTypes from './actionTypes';
export const authStart = () => {
return {
type: actionTypes.AUTH_START
}
}
export const authSuccess = token => {
return {
type: actionTypes.AUTH_SUCCESS,
token: token
}
}
export const authFail = error => {
return {
type: actionTypes.AUTH_FAIL,
error: error
}
}
export const logout = () => {
localStorage.removeItem('token');
return {
type: actionTypes.AUTH_LOGOUT
};
}
export const authLogin = (userData) => {
return dispatch => {
dispatch(authStart());
axios.post('http://localhost:8000/rest-auth/login/', userData)
.then(res => {
const token = res.data.key;
localStorage.setItem('token', token);
dispatch(authSuccess(token));
})
.catch(err => {
dispatch(authFail(err))
})
}
}
authReducer.js
import * as actionTypes from '../actions/actionTypes';
import { updateObject } from '../utility';
const initialState = {
isAuthenticated: null,
token: null,
error: null,
loading: false
}
const authStart = (state, action) => {
return updateObject(state, {
isAuthenticated: false,
error: null,
loading: true
});
}
const authSuccess = (state, action) => {
return updateObject(state, {
isAuthenticated: true,
token: action.token,
error: null,
loading: false
});
}
const authFail = (state, action) => {
return updateObject(state, {
error: action.error,
loading: false
});
}
const authLogout = (state, action) => {
return updateObject(state, {
token: null
});
}
export default function (state = initialState, action) {
switch (action.type) {
case actionTypes.AUTH_START: return authStart(state, action);
case actionTypes.AUTH_SUCCESS: return authSuccess(state, action);
case actionTypes.AUTH_FAIL: return authFail(state, action);
case actionTypes.AUTH_LOGOUT: return authLogout(state, action);
default:
return state;
}
}
articleList.js
import React, { useState, useEffect } from 'react';
import { Container, Row, Col } from 'react-bootstrap';
import Card from '../components/Card'
import FullPageLoader from "../components/FullPageLoader";
import axios from 'axios';
import { connect } from 'react-redux'
const NewsList = () => {
const [items, setItems] = useState([])
const [isLoading, setLoading] = useState(true)
const [isAuthenticated, setAuth] = useState(true); //i don't know how to authenticate it when i also login
useEffect((props) => {
const fetchItems = async () => {
try {
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Token ${props.token}`
}
}
const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/`, config);
setItems(res.data)
setLoading(false);
}
catch (err) {
console.log(`😱 Axios request failed: ${err}`);
}
}
fetchItems()
})
}, [items]);
return (
<Container className="mt-5">
< div className="bread-header" >
<h5>Dashboard</h5>
</div >
<hr />
<Row>
<Col sm={8}>
{
isLoading ? <FullPageLoader /> :
<div>
{itemData.map((item, index) => (
<Card key={index} item={item} isAuthenticated={isAuthenticated} ></Card>
))}
</div>
}
</Col>
</Row>
</Container >
)
}
const mapStateToProps = (state) => {
return {
isAuthenticated: state.auth.token,
}
}
export default connect(mapStateToProps)(NewsList)
Look at this thread: Sending the bearer token with axios
You need to add the token to the request as a header.