How can i access the cookie sent as a response from express in react js? - reactjs

I am using mern stack to make an application. For authentication i am using toke auth with passport authentication and for security reasons i am sending token in cookie. I have a login call which returns a cookie with response. The snippet is below:
res.cookie("cookie_token", token, { maxAge: 84600 });
res.send({
status: "success"
});
I can see the cookie in postman and even in browser in network(xhr request).
I am using axios for making call to the login api in react js.
axios.get(myapiurl, {
headers: {
email: fields.email,
password: fields.password,
"access-control-allow-origin": "*"
}
})
.then(res => {
console.log(res);
}).catch((err) => {
console.log(err);
});
Though i can't find a snippet to access the cookie in react js. How can i parse it? I can't see cookie in response of axios though? How can i access it.

Please try this. Snippet from mdn.
function getCookie(sKey) {
if (!sKey) { return null; }
return document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + sKey.replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1") || null;
}
export function getLoginInfo() {
const cookieToken = getCookie('cookie_token')
console.log(cookieToken)
}

Related

Django backend authentication with NextJS frontend form - best practices

I have an API hub that I've built in Django and a frontend end application I've built in NextJS. I'm currently working on authenticating to the Django API in Nextjs and I'm curious about best practices.
Currently, the NextJS app posts the users username/password to an endpoint. This endpoint either returns the users token or the error illustrating the issue.
React
const login = async () => {
let token = await axios.post('/api/accounts/', {
email: email,
password: password
}).then(r => r.data.token).catch(function (error) { console.log(error) })
if (token) {
router.push({
pathname: '/home/',
query: { token: token },
})
}
}
nexjs server api/accounts
export default async (req, res) => {
if (req.method === 'POST') {
try {
// retrieve payment intent data
const {data} = await axios.post('https://website/api/api-token-auth/', req.body)
res.status(200).send(data)
} catch (err) {
res.status(500).json({ statusCode: 500, message: err.message })
}
} else {
res.setHeader('Allow', 'POST')
res.status(405).end('Method Not Allowed')
}
}
Django API
#csrf_exempt
#api_view(["POST"])
#permission_classes((AllowAny,))
def obtain_auth_token(request):
email = request.data.get("email")
password = request.data.get("password")
if email is None or password is None:
return Response({'error': 'Please provide both email and password'},
status=HTTP_400_BAD_REQUEST)
user = authenticate(email=email, password=password)
if not user:
return Response({'error': 'Invalid Credentials'},
status=HTTP_404_NOT_FOUND)
token, _ = Token.objects.get_or_create(user=user)
return Response({'token': token.key},
status=HTTP_200_OK)
Once I receive the token I push the user to the homepage.
My questions are:
Is how I'm authenticating users a good way to do this? Am I overlooking something? This is the first time I've attempted to authenticate to something I've built so I want to get this right.
How should I store this token? What is "best practice" when it comes to authentication creds? I've thought about passing the token around to every component that needs it. I've also peeked at using LocalStorage but again am unsure what most people do in these situations.
Any help you all can provide would be much appreciated!
Thanks in advance!

How do I fix 'The access token is from wrong audience or resource.' when trying to access Azure's REST api using an MSAL token

I'm creating a node web app that needs to integrate with some azure services using Azure REST API. I'm using the node MSAL library for user login and retrieving an access token for making requests to the Azure REST api. I'm able to login a user successfully and retrieve an access token. However, when I try to make a request to Azure's REST api I am receiving a 401 error that says error="invalid_token", error_description="The access token is from wrong audience or resource."
The web app itself is built with Node LTS and React v16.8.6. It has been deployed in Azure and registered with active directory.
I'm using MSAL v1.0.1 to login a user and retrieve a token when the user lands on the login page.
login.js
import React, { Component } from 'react';
import * as Msal from 'msal';
let msalConfig = {
auth: {
clientId: process.env.REACT_APP_CLIENT_ID,
authority: `https://login.microsoftonline.com/process.env.REACT_APP_TENANT_ID'`,
navigateToLoginRequestUrl: false,
redirect_uri: 'http://localhost:3000/newEntry',
resource: 'https://management.azure.com/'
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true
}
};
var msalInstance = new Msal.UserAgentApplication(msalConfig);
var tokenRequest = {
scopes: ['https://management.azure.com/']
}
class Login extends Component {
constructor(props) {
super(props);
this.state = {
response: null,
};
}
componentWillMount() {
// prevent login loop by checking for logged in user and then acquire a token if logged in
if (!msalInstance.getAccount() && !msalInstance.isCallback(window.location.hash)) {
this.login();
} else {
msalInstance.acquireTokenSilent(tokenRequest)
.then(res => localStorage.setItem('access_token', res.accessToken))
.catch(err => console.error(err))
}
}
login = () => {
msalInstance.handleRedirectCallback((error, response) => {
if (error) console.error(error);
console.log(response);
})
msalInstance.loginRedirect(tokenRequest);
}
render() {
return (
<div>
<h2>Login</h2>
</div>
)
}
}
export default Login;
I am successfully returning an access token and putting it in local storage.
On a separate page I am retrieving the MSAL access token from local storage and using it to make a request to retrieve all resources associated with my Azure subscription.
componentWillMount() {
let token = localStorage.getItem('access_token');
let url = 'https://management.azure.com/subscriptions/process.env.REACT_APP_SUBSCRIPTION_ID/resource?api-version=2018-02-14'
fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => console.log(response))
.catch(err => console.error(err));
}
I suspect I'm getting the error because there is some discrepancy between the resource value sent with the login request and the scope value sent with the token request.
I've attempted changing the resource value to 'resource': 'https://management.core.windows.net/' per Azure: The access token has been obtained from wrong audience or resource but that didn't change anything.
I've also attempted various scopes including https://management.azure.com/user_impersonation and https://management.azure.com//user_impersonation following this example Access Token do not include access for API with MSAL
The get method is default, and the problem might be in 'Authorization': `Bearer ${token}`.
Sometimes people use different rules, like 'Authorization': token, or 'Token': `Bearer ${token}`.
I see some API using 'S-token': token. try that. I thinkit is because the token did get there.
You are using msal, so resource parameter is not needed in your msalConfig. You can remove it.
Change the scopes to scopes: ['https://management.azure.com/.default'].
So I ended up switching to the ADAL library to see if I would get the same error and I did. I did however realize the resource request URL wasn't correct. The api-version wasn't an accepted version. Once I switched it to 2018-02-01 the request returned 200.

Get csrftoken cookie with React

I am making my first app with React, interacting with a Django Rest Framework back-end application. They both are running in their local servers.
I found that requests from the React front-end (that are sent with Axios) requiere a csrftoken cookie. I read and followed Django Documentation about it, but I always get an undefined csrftoken cookie.
This is the code of the request:
handleClick() {
var csrftokenCookie = Cookies.get('csrftoken');
console.log(csrftokenCookie);
const axios = require('axios');
axios.post('http://127.0.0.1:8000/es/api-auth/login/', {
next: '/',
username: 'some_name',
password: 'secret'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
}
I print to console the result of the Cookies.get('csrftoken'), and I can see that it is always undefined.
I don't know what I am missing in order to be able to get the csrftoken cookie.

spotify api axios react post request 403 error

makePlaylist = event => {
event.preventDefault()
let token = localStorage.getItem('token')
let playlist = {name: this.state.text, public:false}
axios.post(
`https://api.spotify.com/v1/users/${this.state.user_id}/playlists`, playlist,
{headers: {
"Authorization": 'Bearer ' + token
}
}
)
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
}
and I get the following error
https://api.spotify.com/v1/users/my_user_id_here/playlists 403 error
I looked up the documentation online at
https://developer.spotify.com/documentation/web-api/reference/playlists/create-playlist/
and it looks like I'm setting things up as far as I can tell. Anyone know what I'm doing wrong with the request? I know the access token is valid.
"Trying to create a playlist when you do not have the user’s authorization returns error 403 Forbidden." Make sure that the Spotify app that you made in Dashboard has the proper scope permissions on the user you are trying to create the playlist for. Here is the scope for creating a private playlist: https://developer.spotify.com/documentation/general/guides/scopes/#playlist-modify-private
Here is the tutorial for setting up authorization with passing in a scope:
https://developer.spotify.com/documentation/general/guides/authorization-guide/

How to implement login authentication using react-redux?

After a bit of research, JWT is commonly used for login authentication because of its compact nature and easiness to parse. I have settled on using JWT. However, my question is on how to embed this in my redux paradigm. Assuming we have a sign up form, when a user fills in his or her credentials and clicks a submit button, this will invoke an action to create an action to create a JWT. Now, this action goes to the back-end of my application and the back-end of my application calls the JWT API? So this action is an asynchronous/rpc call? Also, how does routing happen exactly? I have used react-router before, but using a boilerplate. I am building this web app from scratch and so I am a bit confused on where to deal with the routing and where do I pass this token exactly that I obtain from the server the first time? Is the token used every time a user does a request? How does the client know about this token every time it does the request so that it would keep a user authenticated?
When a user submits his credentials (email/password) your backend authenticates that for the first time and only this time does the backend use these credentials. On authentication your backend will create a JWT with some of the user information, usually just the user ID. There are plenty of JWT Libraries and even jwt-decode for javascript to do this. The backend will respond with this JWT where the front-end will save it (ie, localStorage.setItem('authToken', jwt)) for every subsequent request.
The user will send a request with the JWT in the request header under the Authorization key. Something like:
function buildHeaders() {
const token = localStorage.getItem('authToken')
return {
"Accept": "application/json",
"Content-Type": "application/json"
"Authorization": `${token}`
}
}
Your backend will now decode and authenticate the JWT. If it's a valid JWT the request continues, if not it's rejected.
Now with React-Router you can protect authenticated routes with the onEnter function. The function you provide does any necessary checks (check localStorage for JWT and if a current user). Typically I've done this:
const _ensureAuthenticated = (nextState, replace) => {
const { dispatch } = store
const { session } = store.getState()
const { currentUser } = session
const token = localStorage.getItem("phoenixAuthToken")
if (!currentUser && token) { // if no user but token exist, still verify
dispatch(Actions.currentUser())
} else if (!token) { // if no token at all redirect to sign-in
replace({
pathname: "/sign-in",
state: { nextPathname: nextState.location.pathname}
})
}
}
You can use this function in any route like so:
<Route path="/secret-path" onEnter={_ensureAuthenticated} />
Check out jwt.io for more information on JWT's and the react-router auth-flow example for more information on authentication with react-router.
I personally use Redux saga for async API calls, and I'll show You the flow I've been using for JWT authorization:
Dispatch LOG_IN action with username and password
In your saga You dispatch LOGGING_IN_PROGRESS action to show e.x. spinner
Make API call
Retrieved token save e.x. in localstorage
Dispatch LOG_IN_SUCCESS or LOG_IN_FAILED to inform application what response did You get
Now, I always used a separate function to handle all my requests, which looks like this:
import request from 'axios';
import {get} from './persist'; // function to get something from localstorage
export const GET = 'GET';
export const POST = 'POST';
export const PUT = 'PUT';
export const DELETE = 'DELETE';
const service = (requestType, url, data = {}, config = {}) => {
request.defaults.headers.common.Authorization = get('token') ? `Token ${get('token')}` : '';
switch (requestType) {
case GET: {
return request.get(url, data, config);
}
case POST: {
return request.post(url, data, config);
}
case PUT: {
return request.put(url, data, config);
}
case DELETE: {
return request.delete(url, data, config);
}
default: {
throw new TypeError('No valid request type provided');
}
}
};
export default service;
Thanks to this service, I can easily set request data for every API call from my app (can be setting locale also).
The most interesting part of it should be this line:
request.defaults.headers.common.Authorization = get('token') ? `Token ${get('token')}` : '';`
It sets JWT token on every request or leave the field blank.
If the Token is outdated or is invalid, Your backend API should return a response with 401 status code on any API call. Then, in the saga catch block, you can handle this error any way You want.
I recently had to implement registration and login with React & Redux as well.
Below are a few of the main snippets that implement the login functionality and setting of the http auth header.
This is my login async action creator function:
function login(username, password) {
return dispatch => {
dispatch(request({ username }));
userService.login(username, password)
.then(
user => {
dispatch(success(user));
history.push('/');
},
error => {
dispatch(failure(error));
dispatch(alertActions.error(error));
}
);
};
function request(user) { return { type: userConstants.LOGIN_REQUEST, user } }
function success(user) { return { type: userConstants.LOGIN_SUCCESS, user } }
function failure(error) { return { type: userConstants.LOGIN_FAILURE, error } }
}
This is the login function of the user service that handles the api call:
function login(username, password) {
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
};
return fetch('/users/authenticate', requestOptions)
.then(response => {
if (!response.ok) {
return Promise.reject(response.statusText);
}
return response.json();
})
.then(user => {
// login successful if there's a jwt token in the response
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('user', JSON.stringify(user));
}
return user;
});
}
And this is a helper function used to set the Authorization header for http requests:
export function authHeader() {
// return authorization header with jwt token
let user = JSON.parse(localStorage.getItem('user'));
if (user && user.token) {
return { 'Authorization': 'Bearer ' + user.token };
} else {
return {};
}
}
For the full example and working demo you can go to this blog post

Resources