react native expo:Google auth does not return user data - react-native

I am following the process in official documentation here
https://docs.expo.io/versions/latest/sdk/google
My source code looks like this
export async function signInWithGoogleAsync() {
try {
const result = await Expo.Google.logInAsync({
androidClientId: '272284064749-p61ji1pgisvk1d5s2k7kc56kch0vssi9.apps.googleusercontent.com',
// iosClientId: '272284064749-p61ji1pgisvk1d5s2k7kc56kch0vssi9.apps.googleusercontent.com',
scopes: ['profile', 'email'],
});
if (result.type === 'success') {
return getUserInfo(result.accessToken);
} else {
return {cancelled: true};
}
} catch(e) {
return {error: true};
}
}
Get user information:
async function getUserInfo(accessToken) {
let Info = await fetch('https://www.googleapis.com/userinfo/v2/me', {
headers: { Authorization: `Bearer ${accessToken}`},
});
return console.log(JSON.stringify(Info));
}
Surprisingly, instead giving user data it logs this to console
{"type":"default","status":200,"ok":true,"headers":{"map":{"alt-svc":"quic=\":443\"; ma=2592000; v=\"44,43,39,35\"","x-content-type-options":"nosniff","cache-control":"public, max-age=0","x-frame-options":"SAMEORIGIN","server":"ESF","vary":"Referer","date":"Thu, 25 Oct 2018 05:14:19 GMT","x-xss-protection":"1; mode=block","content-type":"application/json; charset=UTF-8","expires":"Mon, 01 Jan 1990 00:00:00 GMT"}},"url":"https://www.googleapis.com/userinfo/v2/me","_bodyInit":{"_data":{"size":370,"offset":0,"blobId":"bfbedf5e-e2d7-45f0-b97c-483f814307dc"}},"_bodyBlob":{"_data":{"size":370,"offset":0,"blobId":"bfbedf5e-e2d7-45f0-b97c-483f814307dc"}}}

Expo 26.0.0 onward, the google user info comes as a part of the result object.
Just as you can access result.accessToken, you can access the user info with result.user.
Hope it helps you and anyone else who faces this issue.

Related

React Native Facebook User Photos is Denied

I have a react native app and i can login with facebook. However I can't get the users photo. First of all FB hash key is correct and my app is in live mode. I sent the app to APP REVIEW and the photos are always denied by team and they are telling me they can't get the photos of the users. I use "react-native-fbsdk-next": "^4.3.0" and we use our own api url for photos, not using Graph Api of FB. There is [user_photos] as well beside public_profile. Does anyone know the reason for this ? After I login to Facebook, i try to upload photo via FB and it displays a pop up saying " facebook photos permission is denied. This permission allows your app to read photos of Facebook". Why facebook team denies user photo access ? what else should do to make it work ? My login code implementation is below. I could not find anything on Google regarding this kind of issue. Please help
export const facebookLogin = snackBarBottomMargin => {
return async dispatch => {
try {
const result = await LoginManager.logInWithPermissions([
'public_profile',
'user_photos',
]);
if (!result.isCancelled) {
const data = await AccessToken.getCurrentAccessToken();
if (data && data.accessToken) {
await storage.storeData(
PREFERENCES.FB_ACCESS_TOKEN,
JSON.stringify(data),
);
return data;
} else {
console.log('Facebook result fetch token error cancelled');
return false;
}
} else {
console.log('Login cancelled');
return false;
}
} catch (error) {
dispatch(
showSnackbar(strings.login.facebookLoginError, snackBarBottomMargin),
);
return false;
}
};
};
export function handleFetchFBPhotos(accessToken, after) {
return async dispatch => {
function onSuccess(success) {
dispatch(fetchMediaSuccess(success));
console.log('success', success);
return success;
}
function onError(error) {
dispatch(fetchMediaFailed(error));
console.log('error', error);
return error;
}
try {
dispatch(fetchMediaRequest(true));
const config = {
baseURL: Config.FACEBOOK_BASE_URL,
params: {
type: 'uploaded',
fields: 'images',
after,
},
headers: {Authorization: `Bearer ${accessToken}`},
};
const response = await axios.get(FACEBOOK_PHOTOS, config);
if (response.data && response.data.data) {
console.log('response.data', response.data);
console.log('response.data.data', response.data.data);
console.log('onSuccess(response.data)', onSuccess(response.data));
return onSuccess(response.data);
}
} catch (error) {
const errorObj = getErrorResponse(
error,
Config.FACEBOOK_BASE_URL + FACEBOOK_PHOTOS,
);
console.log('onError(errorObj.message)', onError(errorObj.message));
return onError(errorObj.message);
}
};
}

How to get gender and country details from google sign in?

In my react native project I've implemented Google signin functionality with firebase. When I signin using Google I get successfull response.
GoogleSignInMethods
export const googleConfigure = () =>
GoogleSignin.configure({
webClientId: FIREBASE_WEB_CLIENT_ID,
offlineAccess: true,
forceCodeForRefreshToken: true,
accountName: '',
});
export const signIn = async () => {
try {
await GoogleSignin.hasPlayServices();
const info = await GoogleSignin.signIn();
console.warn({userInfo: info});
// set user into state
} catch (error) {
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
console.log('Sign in cancelled');
} else if (error.code === statusCodes.IN_PROGRESS) {
console.log('Sign in inprogress');
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
console.log('Play service not available in this device');
} else {
console.log('Something error happened', error);
}
}
};
userInfo
user {
email: "data comes here"
familyName: "data comes here"
givenName: "data comes here"
id: "data comes here"
name: "data comes here"
photo: "data comes here"
}
for my project I need user's gender and country details. How can I retrieve it?
You cannot retrieve users' gender using google sign in for react-native as the package does not have such functionality implemented. What you can do is call another google api with the token you received from calling the sign in function
await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn();
if (userInfo) {
const { accessToken } = await GoogleSignin.getTokens();
const response = await axios({
method: 'GET',
headers: {
Authorization: `Bearer ${accessToken}`,
},
url: `https://people.googleapis.com/v1/people/${userInfo.user.id}?personFields=genders`,
});
console.log(response); // You should have the info here
}

Migrate ADAL.js to MSAL.js

I have a SPA which uses the solution provided here to authenticate with Azure AD and everything works as expected. Now I want to migrate this to use MSAL.js.
I use below for login:
import * as MSAL from 'msal'
...
const config = {
auth: {
tenantId: '<mytenant>.com',
clientId: '<myclientid>',
redirectUri: <redirecturi>,
},
cache: {
cacheLocation: 'localStorage',
}
};
const tokenRequest = {
scopes: ["User.Read"]
};
export default {
userAgentApplication: null,
/**
* #return {Promise}
*/
initialize() {
let redirectUri = config.auth.redirectUri;
// create UserAgentApplication instance
this.userAgentApplication = new MSAL.UserAgentApplication(
config.auth.clientId,
'',
() => {
// callback for login redirect
},
{
redirectUri
}
);
// return promise
return new Promise((resolve, reject) => {
if (this.userAgentApplication.isCallback(window.location.hash) || window.self !== window.top) {
// redirect to the location specified in the url params.
}
else {
// try pull the user out of local storage
let user = this.userAgentApplication.getUser();
if (user) {
resolve();
}
else {
// no user at all - go sign in.
this.signIn();
}
}
});
},
signIn() {
this.userAgentApplication.loginRedirect(tokenRequest.scopes);
},
And then I use below to get the token:
getCachedToken() {
var token = this.userAgentApplication.acquireTokenSilent(tokenRequest.scopes);
return token;
}
isAuthenticated() {
// getCachedToken will only return a valid, non-expired token.
var user = this.userAgentApplication.getUser();
if (user) {
// get token
this.getCachedToken()
.then(token => {
axios.defaults.headers.common["Authorization"] = "Bearer " + token;
// get current user email
axios
.get('<azureapi-endpoint>' + '/GetCurrentUserEmail')
.then(response => { })
.catch(err => { })
.finally(() => {
});
})
.catch(err => { })
.finally(() => { });
return true;
}
else {
return false;
}
},
}
but after login I get below error:
Access to XMLHttpRequest at 'https://login.windows.net/common/oauth2/authorize?response_type=code+id_token&redirect_uri=<encoded-stuff>' (redirected from '<my-azure-api-endpoint>') from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Also the token that I get seems to be invalid as I get 401 errors trying to call api using the token. Upon checking the token against https://jwt.io/ I get an invalid signature.
I really appreciate anyone's input as I've already spent good few days and haven't got anywhere yet.
I'm not sure if this is your issue. however, for msal.js, in the config, there is no tenantId parameter, it's supposed to be authority. Here is a sample for graph api using msal.js
https://github.com/Azure-Samples/active-directory-javascript-graphapi-v2
specifically: the config is here: https://github.com/Azure-Samples/active-directory-javascript-graphapi-v2/blob/quickstart/JavaScriptSPA/authConfig.js
as per here, https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-js-initializing-client-applications it is supposed to be hitting login.microsoftonline.com not login.windows.net

How can I remove the `GET http://localhost:5000/api/users/profile 401 (Unauthorized)` showing in the console?

I am setting up refresh and access token system for my Vue web application. http://localhost:5000/api/users/profile is the URL of my POST request. I expect an error when someone tries to access and their access token has expired. I use interceptors from Axios in order to generate a brand new access token when such error appears. Everything works fine. However, I've spent a lot of time trying to figure out how to get rid of the GET http://localhost:5000/api/users/profile 401 (Unauthorized) in console. Is there any way to rid of it? Any help would be appreciated.
Getting profile:
getProfile: async (context) => {
context.commit('PROFILE_REQUEST')
let res = await axios.get('http://localhost:5000/api/users/profile')
context.commit('USER_PROFILE', res.data.user);
return res;
}
Interceptor:
axios.interceptors.response.use((res) => {
return res;
}, async (err) => {
const originalRequest = err.config;
if (err.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
const refreshToken = Cookies.get('jid');
return axios.post('http://localhost:5000/api/users/refresh-token', { refreshToken }).then((res) => {
axios.defaults.headers.common['Authorization'] = `Bearer ${res.data.accessToken}`;
originalRequest.headers['Authorization'] = `Bearer ${res.data.accessToken}`;
originalRequest.baseURL = undefined;
return axios(originalRequest);
})
}
return Promise.reject(err);
});
}

Unhandled promise rejection: Error: Request failed with status code 500

I am trying to call an api and I get the error "Unhandled promise rejection: Error: Request failed with status code 500". I dunno how did I get the error.I put the api call in componentDidMount. I am not sure whether the error comes from the redux implementation or from how I called the api.
This is how I called the api. After a successful login, I put the username as a token and use it to call another api.
state={
username: '',
semcode: [
{}
]
}
componentWillMount() {
AsyncStorage.getItem('Login_token').then((token) => {
console.log('this is coursescreen',token);
let Login_token = token;
this.setState({ username: Login_token });
});
}
componentDidMount(){
this.props.getSemcode(this.state.username);
}
componentWillReceiveProps(nextProps) {
console.log('xx',nextProps);
if (nextProps.semCode != undefined) {
this.setState({ semcode: nextProps.semCode });
}
}
This is how I wrote my action file:
export const getSemcode = (username) => async dispatch => {
let param = {
nomatrik: username,
}
console.log(`${helper.ROOT_URL}/result/GetListOfKodSesiSem`)
let code_res = await
axios.post(`${helper.ROOT_URL}/result/GetListOfKodSesiSem`, param)
console.log(code_res.data);
if (code_res.data.length > 0) {
const { code } = code_res.data;
dispatch({ type: SEMCODE_FETCH_SUCCESS, payload: { semCode: code }});
}
}
This is how I wrote my reducer:
import { SEMCODE_FETCH_SUCCESS} from '../actions/types';
const INITIAL_STATE={
semCode:[],
}
export default function (state=INITIAL_STATE, action){
switch(action.type){
case SEMCODE_FETCH_SUCCESS:
return action.payload
default:
return state;
}
}
Can anyone help me pleaseeeeee
Error Message
Error received from axios.post: {"config":{"transformRequest":
{},"transformResponse":{},"timeout":0,"xsrfCookieName":"XSRF-
TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"headers":
{"Accept":"application/json, text/plain, /","Content-
Type":"application/json;charset=utf-8"},
"method":"post","nomatrik":"BB16160907",
"url":"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem","data":"
{\"Accept\":\"application/json\",\"Content-
Type\":\"application/json\"}"},"request":
{"UNSENT":0,"OPENED":1,"HEADERS_RECEIVED":2,"LOADING":3,"DONE":4,
"readyState":4,"status":500,"timeout":0,"withCredentials":true,"upload":
{},"_aborted":false,"_hasError":false,"_method":"POST","_response":"
{\"Message\":\"An error has occurred.\"}",
"_url":"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem",
"_timedOut":false,"_trackingName":"unknown",
"_incrementalEvents":false,"responseHeaders":{"Date":"Sat, 30 Dec 2017
03:58:25
GMT","Content-Length":"36","X-Powered-By":"ARR/3.0","X-AspNet-
Version":"4.0.30319","Expires":"-1","Content-Type":"application/json;
charset=utf-8","Server":"Microsoft-IIS/10.0","Pragma":"no-cache","Cache-
Control":"no-cache"},"_requestId":null,"_headers":
{"accept":"application/json, text/plain, /","content-
type":"application/json;charset=utf-
8"},"_responseType":"","_sent":true,"_lowerCaseResponseHeaders":{"date":"Sat,
30 Dec 2017 03:58:25
GMT","content-length":"36","x-powered-by":"ARR/3.0","x-
aspnet-version":"4.0.30319","expires":"-1","content-type":"application/json; charset=utf-8","server":"Microsoft-IIS/10.0","pragma":"no-cache","cache-
control":"no-cache"},"_subscriptions":[],"responseURL":
"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem"},"response":{"data":
{"Message":"An error has
occurred."},"status":500,"headers":{"date":"Sat, 30 Dec 2017 03:58:25
GMT","content-length":"36","x-powered-by":"ARR/3.0","x-
aspnet-version":"4.0.30319","expires":"-1","content-type":"application/json; charset=utf-8","server":"Microsoft-IIS/10.0","pragma":"no-cache","cache-
control":"no-cache"},"config":{"transformRequest":{},"transformResponse":
{},"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-
TOKEN","maxContentLength":-1,"headers":{"Accept":"application/json,
text/plain,
/","Content-Type":"application/json;charset=utf-8"},"method": "post","nomatrik":"BB16160907",
"url":"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem","data":"
{\"Accept\":\"application/json\",\"Content-
Type\":\"application/json\"}"},"request":
{"UNSENT":0,"OPENED":1,"HEADERS_RECEIVED":2,"LOADING":3,"DONE":4,
"readyState":4,"status":500,"timeout":0,"withCredentials":true,"upload":
{},"_aborted":false,"_hasError":false,"_method":"POST","_response":"
{\"Message\":\"An error has occurred.\"}",
"_url":"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem",
"_timedOut":false,"_trackingName":"unknown","_incrementalEvents":false, "responseHeaders":{"Date":"Sat, 30 Dec 2017 03:58:25 GMT","Content-
Length":"36","X-Powered-By":"ARR/3.0","X-AspNet-
Version":"4.0.30319","Expires":"-1","Content-Type":"application/json;
charset=utf-8","Server":"Microsoft-IIS/10.0","Pragma":"no-cache","Cache-
Control":"no-cache"},"_requestId":null,"_headers":
{"accept":"application/json, text/plain, /","content-
type":"application/json;charset=utf-
8"},"_responseType":"","_sent":true,"_lowerCaseResponseHeaders":{"date":"Sat,
30 Dec 2017 03:58:25
GMT","content-length":"36","x-powered-by":"ARR/3.0","x-
aspnet-version":"4.0.30319","expires":"-1","content-type":"application/json; charset=utf-8","server":"Microsoft-IIS/10.0","pragma":"no-cache","cache-
control":"no-cache"},"_subscriptions":
[],"responseURL":"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem"}}}
Login action:
export const attemptLogin = (username, password) => async dispatch => {
let param = {
txtNomatrik: username,
txtPwd: password,
public_key: helper.PUBLIC_KEY,
secret_key: helper.SECRET_KEY
}
console.log(`${helper.ROOT_API_URL}/v1/basic/ad/std/login`)
let login_res = await
axios.post(`${helper.ROOT_API_URL}/v1/basic/ad/std/login`, param)
console.log(login_res.data);
await AsyncStorage.setItem('jwtToken',login_res.data.token);
if (login_res.data.status == 'Successful login') {
const { login } = login_res.data;
dispatch({ type: LOGIN_SUCCESS});
}
}
Problem
Your request is failing because you are not adding the JWT token to the headers.
Solution
Using Axios and with your code this should work. Evidently our big problem here was that you have to pass data even though it is empty. If we do not pass data it fails with error 500.
export const getSemcode = (username) => async dispatch => {
let jwtToken = await AsyncStorage.getItem('jwtToken').then((data) => {
console.log('this is semcode',data);
});
let config = {
method: 'POST',
url: 'url/to/sem',
headers: {
'content-type': 'application/x-www-form-urlencoded',
AntiTemperSignature: jwtToken,
UserID: '123456',
},
data: '',
json: true
};
try {
return axios(config)
.then((response) => {
console.log(response);
if (response.data.length > 0) {
const { code } = response.data;
dispatch({ type: SEMCODE_FETCH_SUCCESS, payload: { semCode: code } });
}
})
.catch((error) => {
console.log(error);
});
}
}
You are looking in the wrong place.
An error code 500 is returned by the remote server when it can't handle the request. In this case, I suspect that the POST to ${helper.ROOT_URL}/result/GetListOfKodSesiSem is failing. The axios library is a promise based library. Wrap the call in a try-catch block like this:
try {
console.log(`${helper.ROOT_URL}/result/GetListOfKodSesiSem`)
let code_res = await
axios.post(`${helper.ROOT_URL}/result/GetListOfKodSesiSem`, param)
console.log(code_res.data);
if (code_res.data.length > 0) {
const { code } = code_res.data;
dispatch({ type: SEMCODE_FETCH_SUCCESS, payload: { semCode: code }});
}
} catch (err) {
console.error(`Error received from axios.post: ${JSON.stringify(err)}`);
}
This will at least give you a view in your debug console on what is happening. You can then coordinate that call with any debug logs from the backend to figure out what the error really is.
Your root cause, however, is that the remote server is returning a Server Error (HTTP code 500) to your client.