Fetching userinfo from Auth0 application in React Native - react-native

I'm using Auth0's react-native-lock widget for user authentication, and after a successful login I'm storing the tokens with AsyncStorage.
If a user comes back to the app, I'd like to be able to skip the login and simply fetch the current userinfo from Auth0. It seems incredibly easy from the the Auth0 API docs but I'm getting back the message "Unauthorized" in my app:
async getUserinfo() {
console.log('getting user info in getUserInfo()');
try {
let response = await fetch('https://xxxxx.auth0.com/userinfo', {
method: 'GET',
headers: {
Authorization: 'Bearer ${this.state.token.accessToken}',
},
});
let responseJson = await response.json();
if(responseJson !== null) {
console.log('Got user info: ' + responseJson.email);
this.setState({ component: Temp, isLoading: false, profile: responseJson});
}
} catch (error) {
console.log('Error in retrieving userinfo from Auth0: ' + error.message);
this.setState({ component: Login, isLoading: false});
}
}
What am I missing? I can't find many examples of using fetch with Auth0, is there a better method I should be using?

Problem identified in the scope of an associated GitHub issue. In case anyone lands here and not where the issue got solved, the problem is that you need to use:
Authorization: 'Bearer ' + this.state.token.accessToken,
Original code tried to access the variable within a string literal 'Bearer ${this.state.token.accessToken}'.

Related

Axios Post React Native Return Undefined Sometimes

Why my axios post return undefined sometimes ?
Check this code :
export const ApiConfigAxios = axios.create({
// * Begin =========================== Configuration API
baseURL: 'https://website.id/index.php',
withCredentials: true,
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": `Basic ${base64data}`,
},
// * End =========================== Configuration API
});
export const ApiRegisterOrLoginUser = async (email, name, picture, givenname, familyname) => {
try {
// * Begin =========================== API
const response = await ApiConfigAxios.post('/AuthenticationAPI', {
email: email,
name: name,
picture: picture,
givenname: givenname,
familyname: familyname,
});
// * End =========================== API
if (response.data.Data.length === 2) {
let results = Object.assign(response.data.Data[0], response.data.Data[1]);
return results;
} else {
return response.data;
}
} catch (err) {
console.error(err);
}
};
The Problem Is :
When I clear data app from android setting and open the app then quickly click the sign in button I will got undefined
But when I clear data app from android setting and open the app then wait at least 3 second before click the sign in button it is working
what is the problem with the axios ?
Found the problem.
The problem is in server side. I have a post value (TOKENS) that cannot be null.
That is a Notification Tokens. It is inside useEffect.
So in my app I check if TOKENS != null (delay until the token generate) then the button login show.
Also to make a better user experience when got undefined I check in my API Axios :
if (typeof response == 'undefined') {
return "FAILED";
}
When user login and receive undefined I will prompt a Message Box rather than loading without end. So user can try login again.

Open screen on login - react native

I have a function that shows me an alert when the username and password are correct, but I want to send me a screen as soon as the username and password are correct, I have tried but I have not been able to do it.
in my attempts I have another validation which is if I log in but it does not validate, it is only verifying that the route exists but so put the password or the wrong email log in, I need it to validate and if the user and password are correct there yes let me log in.
const signIn = async({correo, password}: LoginData) => {
try {
await fetch('https://www.portal.multigobernanza.com/apiMultigobernanza/usuarios/login.php',
{
method:'POST',
headers:{
'Accept': 'application/json',
'content-Type': 'application/json'
},
body: JSON.stringify({"email":correo, "password" : password})
}).then(res => res.json())
.then(resData => {
Alert.alert(resData.message)
console.log(resData);
});
}catch (error) {
dispatch({type: 'addError',
payload: error.response.data.msg || 'Información incorrecta'})
}
};
other validation
const signIn = async({correo, password}: LoginData) => {
try {
const {data} = await cafeApi.post<LoginResponse>('/usuarios/login.php',{correo,password});
dispatch({
type: 'signUp',
payload: {
token: data.token,
user: data.usuario
}
});
await AsyncStorage.setItem('token', data.token);
} catch (error) {
dispatch({type: 'addError',
payload: error.response.data.msg || 'Información incorrecta'})
}
};
GIT
https://github.com/Giovannychvz/react-native
Take a look at how react-navigation suggest authentication flows. To achieve something like that, at the very least you will need a state variable that keeps track of when a user is signed in, and to modify your signIn function to update your state variable

Accessing the response from one GET request within another

I'm working with Vue to interact with an external API on a Drupal website, but in order to do so dynamically per Drupal user, I need to get a token from Drupal first. To do so, I'm trying to do two GET requests. The first gets me a bearer token out of Drupal, and the second uses it to authenticate the third-party API request.
Below is what I'm trying – I'm able to get the token successfully in the first request's response, but not when I try to use it in the header of my second request. If I try hardcoding the token that I see in the console log, it does work, so I know none of that is the issue. It's just that this.jwt['data']['token'] in the second request's headers seems to not pull back the token.
What do I need to adjust in order to access the token from the first response as part of the headers of my second request?
created() {
axios
.get('/jwt/token')
.then(response => {
this.jwt = response
console.log(this.jwt['data']['token']) // this does show what I want to access later
})
},
mounted() {
axios
.get('/comment/doc/' + this.id, {
headers: { Authorization: "Bearer " + this.jwt['data']['token'] } // ...but this doesn't work
})
.then(response => {
this.comments = response
})
},
It's likely the response to the token request has not finished by the time the component mounts, at which point this.jwt is not yet assigned.
I would move the token request into the mounted hook, fetching comments only when the token request succeeds:
export default {
mounted() {
axios
.get('/jwt/token')
.then(tokenResp => {
this.jwt = tokenResp
axios
.get('/comment/doc/' + this.id, {
headers: { Authorization: 'Bearer ' + this.jwt['data']['token'] }
})
.then(commentsResp => {
this.comments = commentsResp
})
})
}
}

Login With React Native using Asyncronous storage

I am implementing login in React Native using Asynchronous storage. Here, when users login successfully, i keep the user object in the Asynchronous storage then i access this information to get the Authentication Key for my API request anytime I want to do a request.
When I login and information is stored in the Asynchronous storage, the current app session fails to get the just stored information hence all my authenticated request fails in this session. When I close the app and restart, I can successfully get the information from the Async storage stored in the previous session and make successful authenticated request.
I do not know what I am missing out in my code as I believe I need to refresh or reload the app internally after a successful login but I do not know how to do this in React Native. Any information or help is needed. Here is my Login code.
HttpRequest.post('api/login', body)
.then((response) => response.json())
.then((responseJson) => {
if(responseJson.succcode == 201){ //successful login
var data = responseJson.user;
data.loggedIn = true;
AsyncStorage.setItem(USER_DATA, JSON.stringify(data)).then(val => {
console.log('just before reload in login')
Actions.menu(); //this solves the after login problem as it goes to the next page only after a successful AsyncStorage save
this.setState({ procesing: false });
})
.catch(err => {
this.setState({ procesing: false, error: "Couldn't log you in! Please try again" });
//console.log("\nCouldn't save to AsyncStorage: " + err + "\n");
});
}
else{
this.setState({ procesing: false, error: "Wrong Username and/or Password! Please try again" });
}
After I have login, my request looks like ;
//for making a post request
post: (url,body) => {
return fetch(url+'?access-token='+this.state.user.auth_key, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
//'Autorization': 'Bearer token2'
},
})
but the user object is gotten from the Async storage as
getUser(){
return AsyncStorage.getItem("USER_DATA").then(value => {
if(JSON.parse(value) == null) {
return false;
} else {
return JSON.parse(value)
}
});
},
Any Information, Ideas, proposed solutions are highly welcome
If you are receiving the information correctly, you can pass the information to the next screen or use the asynchronous repository as it is now.
If use navigation
HttpRequest.post('api/login', body)
.then((response) => response.json())
.then((responseJson) => {
if(responseJson.succcode == 201){ //successful login
var data = responseJson.user;
data.loggedIn = true;
this.setState({ procesing: false });
this.navigation.navigate("LoginScreen",{data: JSON.stringify(data) })
}
else{
this.setState({ procesing: false, error: "Wrong Username and/or Password! Please try again" });
}
LoginScreen
this.state={
data : this.props.navigation.state.params.data
}
If use AsyncStorge
HttpRequest.post('api/login', body)
.then((response) => response.json())
.then((responseJson) => {
if(responseJson.succcode == 201){ //successful login
var data = responseJson.user;
data.loggedIn = true;
AsyncStorage.setItem("USER_DATA", JSON.stringify(data));
this.setState({ procesing: false });
else{
this.setState({ procesing: false, error: "Wrong Username and/or Password! Please try again" });
}
LoginScreen
async componentDidMount() {
let data = await AsyncStorage.getItem("USER_DATA")
}

How to save JWT Token in Vuex with Nuxt Auth Module?

I am currently trying to convert a VueJS page to NuxtJS with VueJS. Unfortunately I have some problems with authenticating the user and I can't find a solution in Google. I only use Nuxt for the client. The API is completely separate in express and works with the existing VueJS site.
In Nuxt I send now with the Auth module a request with username and password to my express Server/Api. The Api receives the data, checks it, and finds the account in MongoDB. This works exactly as it should. Or as I think it should. Now I take the user object and generate the jwt from it. I can debug everything up to here and it works.
Now I probably just don't know how to keep debugging it. I send an answer with res.json(user, token) back to the Nuxt client (code follows below). As I said, in my current VueJS page I can handle this as well. Also in the Nuxt page I see the answer in the dev console and to my knowledge the answer fits.
Now some code.
The login part on the express Api:
const User = require('../models/User')
const jwt = require('jsonwebtoken')
const config = require('../config/config')
function jwtSignUser(user){
const ONE_YEAR = 60 * 60 * 24 * 365
return jwt.sign(user,config.authentication.jwtSecret, {
expiresIn: ONE_YEAR
})
}
module.exports = {
async login (req, res){
console.log(req.body)
try{
const {username, password} = req.body
const user = await User.findOne({
username: username
})
if(!user){
return res.status(403).send({
error: `The login information was incorrect.`
})
}
const isPasswordValid = await user.comparePassword(password)
if(!isPasswordValid) {
return res.status(403).send({
error: `The login information was incorrect.`
})
}
const userJson = user.toJSON()
res.json({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (err) {
console.log(err)
res.status(500).send({
error: `An error has occured trying to log in.`
})
}
}
}
nuxt.config.js:
auth: {
strategies: {
local: {
endpoints: {
login: {url: '/login', method: 'post' },
user: {url: '/user', method: 'get' },
logout: false,
}
}
},
redirect: {
login: '/profile',
logout: '/',
user: '/profile',
callback:'/'
}
}
even tried it with nearly any possible "propertyName".
and, last but not least, the method on my login.vue:
async login() {
try {
console.log('Logging in...')
await this.$auth.loginWith('local', {
data: {
"username": this.username,
"password": this.password
}
}).catch(e => {
console.log('Failed Logging In');
})
if (this.$auth.loggedIn) {
console.log('Successfully Logged In');
}
}catch (e) {
console.log('Username or Password wrong');
console.log('Error: ', e);
}
}
What I really don't understand here... I always get "Loggin in..." displayed in the console. None of the error messages.
I get 4 new entries in the "Network" Tag in Chrome Dev Tools every time I make a request (press the Login Button). Two times "login" and directly afterwards two times "user".
The first "login" entry is as follow (in the General Headers):
Request URL: http://localhost:3001/login
Request Method: OPTIONS
Status Code: 204 No Content
Remote Address: [::1]:3001
Referrer Policy: no-referrer-when-downgrade
The first "user" entry:
Request URL: http://localhost:3001/user
Request Method: OPTIONS
Status Code: 204 No Content
Remote Address: [::1]:3001
Referrer Policy: no-referrer-when-downgrade
Both without any Response.
The second login entry:
Request URL: http://localhost:3001/login
Request Method: POST
Status Code: 200 OK
Remote Address: [::1]:3001
Referrer Policy: no-referrer-when-downgrade
and the Response is the object with the token and the user object.
The second user entry:
Request URL: http://localhost:3001/user
Request Method: GET
Status Code: 200 OK
Remote Address: [::1]:3001
Referrer Policy: no-referrer-when-downgrade
and the Response is the user object.
I think for the login should only the login request be relevant, or I'm wrong? And the user request works because the client has asked for the user route and the user route, always send the answer with the actual user object in my Express API.
Because I think, the problem is in the login response? Here some screenshots from the Network Tab in Chrome Dev Tools with the Request/Response for login.
First login request without response
Second login request
Response to second login request
Do I have to do something with my Vuex Store? I never found any configured Vuex Stores in examples for using the Auth Module while using google so I thougt I do not have to change here anything.
Thats my Vuex Store (Vue Dev Tools in Chrome) after trying to login without success:
{"navbar":false,"token":null,"user":null,"isUserLoggedIn":false,"access":false,"auth":{"user":"__vue_devtool_undefined__","loggedIn":false,"strategy":"local","busy":false},"feedType":"popular"}
There is also some logic I use for my actual VueJS site. I will remove that when the Auth Module is working.
Asked by #imreBoersma :
My /user endpoint on Express looks like:
app.get('/user',
isAuthenticated,
UsersController.getUser)
I first check if the User is authenticated:
const passport = require('passport')
module.exports = function (req, res, next) {
passport.authenticate('jwt', function (err, user) {
if(err || !user) {
res.status(403).send({
error: 'You are not authorized to do this.'
})
} else {
req.user = user
next()
}
})(req, res, next)
}
After that I search the User document in MongoDB and send the document to the client:
const User = require('../models/User')
module.exports = {
[...]
getUser (req, res) {
User.findById(req.user._id, function (error, user){
if (error) { console.error(error); }
res.send(user)
})
}
[...]
}
Feel free to ask for more information.
I think I can answer my own question.
I searched the whole time for an error regarding to my api response.
The problem was the "propertyName" on user endpoint in the nuxt.config.js.
It is set to "user" as default. When I set it to "propertyName: false", than everything works as it should.
auth: {
strategies: {
local: {
endpoints: {
login: {url: '/login', method: 'post', propertyName: 'token' },
user: {url: '/user', method: 'get', propertyName: false },
logout: false,
}
}
}
},