How to get the raw string of cookie using js-cookie - javascript

I am trying to use js-cookie to store access_token as cookies in the cookie strorage. But whenever I set the cookie, it gets displayed like this: %22eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjU5NDIzOTA3LCJpYXQiOjE2NTg1NTk5MDcsImp0aSI6IjAyMmRlMTg2MTk0NzRhYzY5ZThjOTVmOGNhZDE3OTM4IiwidXNlcl9pZCI6Mn0.xkOTI4uO93_YIvlGrcnnKLFjbLZiM_RdNo9J9A8Clk4%22
But I dont want it that way. I weant to get the token without "%22" at the beginning and end.
This is my code. Thank you.
import {createContext, useState, useEffect} from 'react'
import Cookie from "js-cookie";
import jwt_decode from "jwt-decode"
import {useHistory} from 'react-router-dom'
const SetCookie = (cookiename, cookie) => {
Cookie.set(cookiename, cookie)
}
const GetCookie = (cookiename) => {
return Cookie.get(cookiename)
}
const AuthContext = createContext()
export default AuthContext
export const AuthProvider = ({children}) => {
let [authTokens, setAuthTokens] = useState(localStorage.getItem('authTokens') ? JSON.parse(localStorage.getItem('authTokens')):null)
let [user, setUser] = useState(localStorage.getItem('authTokens') ? JSON.parse(localStorage.getItem('authTokens')):null)
const histroy = useHistory()
histroy.push('/')
let loginUser = async (e)=> {
e.preventDefault()
let response = await fetch('http://127.0.0.1:8000/users/login/', {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body:JSON.stringify({'email':e.target.email.value, 'password':e.target.password.value})
})
let data = await response.json()
console.log('response:', response)
if (response.status === 200) {
setAuthTokens(data)
setUser(data)
SetCookie('cookie', JSON.stringify(data.access_token))
localStorage.setItem('authTokens', JSON.stringify(data))
} else{
alert('there was problem signing in')
}
}
let registerUser = async (e)=> {
e.preventDefault()
let response = await fetch('http://127.0.0.1:8000/users/register/', {
method: 'POST',
headers:{
'Content-Type':'application/json'
},
body:JSON.stringify({'username':e.target.username.value, 'email':e.target.email.value, 'password1':e.target.password1.value, 'password2':e.target.password2.value})
})
let data = await response.json()
console.log('response:', response)
if (response.status === 201) {
alert('An email verification message has been sent to your email address')
} else{
alert('Something went wrong! Check your credentials and try again')
}
}
let passwordReset = async (e)=> {
e.preventDefault()
let response = await fetch('http://127.0.0.1:8000/password-reset/', {
method: 'POST',
headers:{
'Content-Type':'application/json'
},
body:JSON.stringify({'email':e.target.email.value})
})
let data = await response.json()
console.log('response:', response)
}
let passwordresetConfirm = async (e)=> {
e.preventDefault()
let response = await fetch('http://127.0.0.1:8000/password-reset-confirm/', {
method: 'POST',
headers:{
'Content-Type':'application/json'
},
body:JSON.stringify({'new_password1':e.target.new_password1.value, 'new_password2':e.target.new_password2.value,})
})
let data = await response.json()
console.log('response:', response)
}
let logoutUser = () => {
setAuthTokens(null)
setUser(null)
localStorage.removeItem('authTokens')
histroy.push('/login')
}
let contextData = {
user:user,
loginUser : loginUser,
logoutUser : logoutUser,
registerUser : registerUser,
passwordReset : passwordReset,
passwordresetConfirm : passwordresetConfirm,
}
return(
<AuthContext.Provider value={contextData}>
{children}
</AuthContext.Provider>
)
}

Related

How can I use axios.defaults.baseURL conditionally? [duplicate]

I am having a config file . where i am setting the baseURL for the entire app and also saving the bearer token for the entire API requests. Here i am in situation to add another api . I dont know how to add another baseURL & use this on my API requests.Here i am sharing the code of what i have done.
BASE URL FILE:
import axios from 'axios';
axios.defaults.baseURL = http://localhost:3000/summary;
const setAuthToken = (token) => {
if (token) {
axios.defaults.headers.common.Authorization = `Bearer ${token}`;
} else {
delete axios.defaults.headers.common.Authorization;
}
};
export default setAuthToken;
API ACTION FILE:
export const login = ({ email, password }) => async (dispatch) => {
const userData = {
username: email,
password,
};
try {
const res = await axios.post('/license-api/auth/login', userData, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data.token,
});
} catch (error) {
dispatch({
type: LOGIN_FAIL,
});
}
};
i need to add another url like this in BASE URL FILE
axios.defaults.baseURL = http://localhost:6000/profile
how to add this one and use this in API action file.
Please help me with this.
Thanks in advance
As said you could create two instances of axios and use them as needed:
In you BASE URL file:
import axios from 'axios';
const setAuthToken = (token) => {
if (token) {
axios.defaults.headers.common.Authorization = `Bearer ${token}`;
} else {
delete axios.defaults.headers.common.Authorization;
}
};
const mainAxios = axios.create({
baseURL: 'http://localhost:3000/summary'
});
const profileAxios = axios.create({
baseURL: 'http://localhost:6000/profile'
});
export default setAuthToken;
export { mainAxios, profileAxios };
Then in your API ACTION file:
import { profileAxios } from 'path/to/baseurl';
export const login = ({ email, password }) => async (dispatch) => {
const userData = {
username: email,
password,
};
try {
const res = await profileAxios.post('/license-api/auth/login', userData, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data.token,
});
} catch (error) {
dispatch({
type: LOGIN_FAIL,
});
}
};
The above code works well. I don't see where setAuthToken is called so if you don't want to call setAuthToken manually then you might want to do this.
import axios from "axios";
import { config } from "./config";
const pythonAPI = axios.create({
baseURL: config.pythonServerUrl,
});
const nodeApi = axios.create({
baseURL: config.nodeServerUrl,
});
const setToken = () => {
const token = localStorage.getItem("auth_token");
if (token) {
pythonAPI.defaults.headers.common.Authorization = `Basic ${token}`;
} else {
delete pythonAPI.defaults.headers.common.Authorization;
}
};
const pythonApi = {};
pythonApi.get = async (url) => {
setToken();
return pythonAPI.get(url).catch((e) => e.response);
};
pythonApi.post = async (url, data) => {
setToken();
return pythonAPI.post(url, data).catch((e) => e.response);
};
export { pythonApi, nodeApi };

CreateAsyncThunk Problem with 400 Bad request

i have created a asyncthunk, but when status code is 400, the result of request is still fulfilled, which method is to handle a 400 error with createasyncthunk and fetch api?
This is a action code:
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
import authService from "./auth-service";
// Get user from localStorage
const user = JSON.parse(localStorage.getItem("user"));
const initialState = {
user: user ? user : "",
isError: false,
isSuccess: false,
isLoading: false,
message: "",
};
// Register user
export const register = createAsyncThunk(
"auth/signup",
async (user, thunkAPI) => {
try {
return await authService.register(user);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// Login user
export const login = createAsyncThunk("auth/login", async (user, thunkAPI) => {
try {
return await authService.login(user);
} catch (error) {
const message =
(error.response && error.response.data && error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
});
export const logout = createAsyncThunk("auth/logout", async () => {
await authService.logout();
});
export const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
reset: (state) => {
state.isLoading = false;
state.isSuccess = false;
state.isError = false;
state.message = "";
},
},
extraReducers: (builder) => {
builder
.addCase(register.pending, (state) => {
state.isLoading = true;
})
.addCase(register.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.isSuccess = false;
state.user = "";
})
.addCase(register.fulfilled, (state, action) => {
state.isLoading = false;
state.isError = false;
state.isSuccess = true;
state.message = action.payload;
})
.addCase(login.pending, (state) => {
state.isLoading = true;
})
.addCase(login.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.user = action.payload;
})
.addCase(login.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
state.user = "";
})
.addCase(logout.fulfilled, (state) => {
state.user = "";
});
},
});
export const { reset } = authSlice.actions;
export default authSlice.reducer;
This is a service code:
import React from 'react'
import Cookies from 'js-cookie'
const API_URL = "http://localhost:5000/api/auth/";
const token = Cookies.get('XSRF-Token')
// Register user
const register = async (userData) => {
const response = await fetch(API_URL + "signup", {
method: "POST",
credentials: 'include',
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(userData),
});
const responseData = await response.json();
if (response.ok) {
localStorage.setItem("user", JSON.stringify(responseData));
return responseData;
}
};
// Login user
const login = async (userData) => {
const response = await fetch(API_URL + "login", {
method: "POST",
credentials: 'include',
body: JSON.stringify(userData),
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
});
const responseData = await response.json();
if (response.ok) {
localStorage.setItem("user", JSON.stringify(responseData));
return responseData;
}
};
// Logout user
const logout = () => {
localStorage.removeItem("user");
};
const authService = {
register,
logout,
login,
};
export default authService;
The problem is both register and login action, return a fulfilled even if the code of post request is 400 and my intention is send a message about error
Your code doesn't do anything if response.ok is not truthy. That's what will happen when you get a 4xx status.
So, for example, in this code:
// Register user
const register = async (userData) => {
const response = await fetch(API_URL + "signup", {
method: "POST",
credentials: 'include',
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
// body: JSON.stringify(userData),
});
const responseData = await response.json();
if (response.ok) {
localStorage.setItem("user", JSON.stringify(responseData));
return responseData;
}
};
You just allow the async function to have an undefined return value if response.ok is not truthy. That will resolve the promise, with an undefined resolved value.
Perhaps, you want to turn any non-2xx status into a rejection like this:
// Register user
const register = async (userData) => {
const response = await fetch(API_URL + "signup", {
method: "POST",
credentials: 'include',
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
// body: JSON.stringify(userData),
});
if (response.ok) {
const responseData = await response.json();
localStorage.setItem("user", JSON.stringify(responseData));
} else {
// reject the promise
throw new Error(`status code ${response.status}`)
}
};
You would probably want to do something similar for all your uses of fetch().
Since I find that I want this to be the standard behavior when making requests, I have my own fetchWrapper() function that automatically converts any non-2xx status to a promise rejection so I don't have to code that into every use of fetch().
Here's an example of a fetchWrapper function that turns any http status that is not in the range of 200-299 into a rejected promise:
async function fetchJSON(url, options) {
let response = await fetch(url, options);
if (!response.ok) {
throw new Error(`status code ${response.status}`);
}
return response.json();
}

React Redux problem on dispatching on button

I have a button that dispatches an action to create a post, for some reason the request never proceeds and it fails. This is the action. I have constants that's why types is not on a string
export const createPost = () => async (dispatch, getState) => {
try {
dispatch({
type: POST_CREATE_REQUEST,
});
const {
userLogin: { userInfo },
} = getState();
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.post(
`http://localhost:5000/api/posts`,
config
);
dispatch({
type: POST_CREATE_SUCCESS,
payload: data,
});
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message;
// if (message === 'Not authorized, token failed') {
// dispatch(logout());
// }
dispatch({
type: POST_CREATE_FAIL,
payload: message,
});
}
};
It continues to the POST_CREATE_REQUEST but always errors out to the POST_CREATE_FAIL.
I tried using postman and it works fine, I think the problem is the createPost action can't seem to receive the token even though im logged in as an admin, I'm not sure.
This is the useSelector of the postCreate
const postCreate = useSelector(state => state.postCreate);
const {
loading: loadingCreate,
error: errorCreate,
success: successCreate,
post: createdPost,
} = postCreate;
and this is the useSelector of the user that is logged in, currently as an admin.
const userLogin = useSelector(state => state.userLogin);
const { userInfo } = userLogin;
Rewrite this code
const { data } = await axios.post(
`http://localhost:5000/api/posts`,
config
);
as
const res = await axios.post(
`http://localhost:5000/api/posts`,
config
);
const data = res && res.data
There is already values on my Controller at the backend and just needed to add brackets in the action
from this
const { data } = await axios.post(
`http://localhost:5000/api/posts`,
config
);
to this
const { data } = await axios.post(
`http://localhost:5000/api/posts`, {},
config
);

Strange in React Native not showing err

I have a strange situation with a React Native app.
The part of the code with problems is this:
const request = async (options) => {
const defaults = {baseURL: 'base URL'}
let token = await AsyncStorage.getItem('token');
console.log('this is logged')
if(token) {
console.log("this is logged")
const headers = {
'TokenAuth': token
}
Object.assign(defaults, headers: headers);
}
console.log('this is NOT logged anymore')
options = Object.assign({}, defaults, options);
};
The idea is that i can't see anywhere the javascript error.
The error is on Object.assign(defaults, headers);
Why i can't see it ?
Thank you.
This is the whole component:
import constants from './../constants/constants';
import axios from 'axios';
import { AsyncStorage } from 'react-native';
import * as Utils from '../configs/utils'
const request = async (options) => {
const defaults = {baseURL: constants.BASE_URL}
let token = await AsyncStorage.getItem('token');
if(token) {
const headers = {'TokenAuth': token}
Object.assign(defaults, {headers: headers});
}
options = Object.assign({}, defaults, options);
return axios(options)
.then(response => {
return response.data
} )
.catch( error => {
if (error.response.status == 401) {
Utils.deleteToken();
}
let errResponse = 'Bad Error'
throw errResponse;
});
};
export function getAllTodos() {
return request({method: 'get',
baseURL: constants.BASE_URL,
url: '/api/items',
})
}

React useState hook not working as I would expect

I'm using the useState hook in React and it's behaving in an odd way.
If you look at the example below here is what I would expect: call login, on success it calls setRefreshToken(responseToken) then calls refresh() which references refreshToken set from setRefreshToken. What actually happens is refreshToken is undefined inside of refresh().
I know setState is async but I haven't run in to issues like this before. Am I missing something?
import React, { createContext, useState } from "react";
import jwtDecode from "jwt-decode";
const localStorageKey = "ar_refresh_token";
export const AuthContext = createContext();
export function AuthProvider({ tokenUrl, registerUrl, refreshUrl, children }) {
const [refreshToken, setRefreshToken] = useState(
window.localStorage.getItem(localStorageKey)
);
const [accessToken, setAccessToken] = useState();
const login = async (userId, password) => {
const response = await fetch(tokenUrl, {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
userId,
password
})
});
if (response.status === 201) {
const token = await response.text();
setRefreshToken(token);
window.localStorage.setItem(localStorageKey, token);
await refresh();
}
};
const refresh = async () => {
const response = await fetch(refreshUrl, {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
Authorization: `JWT ${refreshToken}`
}
});
if (response.status === 201) {
const token = await response.text();
setAccessToken(token);
}
};
return (
<AuthContext.Provider
value={{
refreshToken,
accessToken,
login,
refresh
}}
>
{children}
</AuthContext.Provider>
);
}
Full example: https://github.com/analyticsrequired/auth-admin/blob/master/src/AuthContext.js
You are right in that the component will not have been re-rendered before you call refresh, so the refreshToken inside refresh will be the default one.
You could instead pass in the token from login as an argument to refresh and use that and it will work as expected.
const login = async (userId, password) => {
// ...
if (response.status === 201) {
// ...
await refresh(token);
}
};
const refresh = async refreshToken => {
const response = await fetch(refreshUrl, {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
Authorization: `JWT ${refreshToken}`
}
});
// ...
};
You can use useEffect to automatically call refresh whenever refreshToken changes:
...
if (response.status === 201) {
const token = await response.text();
setRefreshToken(token);
window.localStorage.setItem(localStorageKey, token);
//await refresh();
}
...
useEffect(
() => {
// your refresh code
},
[refreshToken]
)
The code inside useEffect will be called on the first render and after refreshToken is changed. So you don't need to call refresh after every call to setRefreshToken.

Categories

Resources