How to get user email using Google Sign In expo Auth Session? - react-native

At moment im using this snippet of code to sign in to google, but i cant get user email… anyone know how to do this?
var LoginGoogle = () => {
const [request, response, promptAsync] = Google.useAuthRequest({
androidClientId: 'xxxxxxx.apps.googleusercontent.com',
expoClientId: 'xxxxxxx.apps.googleusercontent.com'
},{
scopes: ["email"]
},{});
React.useEffect(() => {
if (response?.type === 'success') {
const { authentication } = response;
console.log(response);
}
}, [response]);
return (
<GoogleSocialButton disabled={!request} onPress={() => {promptAsync()}} />
)
}
response returns object with links instead of email

I wish this is written in the expo docs. I would like to add a few points from the first answer:
First if you need code snippets on how to fetch user data after getting the access token, you can refer to this github issue: https://github.com/expo/expo/issues/8384
access token can be received by the following code after receiving the response object:
const { authentication: { accessToken } } = response;
then, you can create a function like this:
async function fetchUserInfo(token) {
const response = await fetch('https://www.googleapis.com/oauth2/v3/userinfo', {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
},
});
return await response.json();
}
and get the user object (which contains the user email, profile, photo, etc) by something like this inside an async function:
const user = await fetchUserInfo(accessToken);
But NOTE for the user object, using https://www.googleapis.com/oauth2/v2/userinfo and https://www.googleapis.com/oauth2/v3/userinfo, will yield slightly different result/object ; in particular for v3, since Google implements the OpenID Connect API, there is no "id" attribute anymore, "id" will be called "sub".
sources:
How to identify a Google OAuth2 user?
https://developers.google.com/assistant/identity/google-sign-in-oauth
https://github.com/expo/expo/issues/8384
Example of a user object in v3:
Object {
"email": "xxxxx#gmail.com",
"email_verified": true,
"family_name": "John Deer",
"given_name": "John",
"hd": "gmail.com",
"locale": "en",
"name": "John Deer",
"picture": "https://lh3.googleusercontent.com/a/asdfjasdklfjaslkf",
"sub": "10998837733652322",
}
Hope this helps someone in the future...!
EDIT: if you need the id_token checkout this one:
expo-auth-session/providers/google Google.useAuthRequest

I am using AuthSession as well in my RN app and I stumbled with this problem. After going through Google API Docs, found out you can pass the access token from the useAuthRequest response to https://www.googleapis.com/oauth2/v3/userinfo?access_token= ACCESS_TOKEN.

Related

Setup Checkout Rest API for Shopify from react mobile app

I am new to shopify, can anyone help me how to setup the checkout API for shopify. I am creating a mobile app with react for a shopify website using API. I tried the one in the shopify docs but it return some error.
post: https://{apikey}:{password}#{hostname}/admin/api/2020-10/checkouts.json
body raw json
{
"checkout": {
"line_items": [
{
"product_id": 5584792125605,
"variant_id": 35877399986341,
"quantity": 1
}
]
}
}
header
X-Shopify-Access-Token : storefront access token
Response
{
"errors": "[API] Invalid API key or access token (unrecognized login or wrong password)"
}
But I've given API key and access token correctly. Is there anything else i should do( I tested this in postman)
Using react native, you have to give the apikey and the password in the Header like this.
getShopifyOrders = () => {
let authorization = base64.encode(
'${Constants.Shopify.key}:${Constants.Shopify.password}'
);
fetch(
'https://${Constants.Shopify.admin_url}/admin/api/2021-04/orders.json',
{
method: "get",
headers: new Headers({
Authorization: 'Basic ${authorization}',
}),
}
)
.then((response) => response.json())
.then((json) => {
console.log(json);
})
.catch((error) => {
console.error(error);
});
};
With Constants.Shopify.key = 'Your_api_key' and Constants.Shopify.password = 'Your_password'
Note : In this code, you have to replace the ' with backsticks ;)

How to get idToken from Expo GoogleSignIn API (expo v32)?

I am trying to setup native Google authentication on react-native using Expo GoogleSignIn API, but can't get idToken for authorized Google User.
It has accessToken in response, but not idToken.
So I am using some straigtforward code like
const result = await GoogleSignIn.initAsync({
isOfflineEnabled: true,
isPromptEnabled: true,
//webClientId: 'webClientId',
clientId // now testing only on Android, so this is irrelevant
});
console.log(result);
Example response:
Object {
"auth": Object {
"accessToken": "accessToken",
"accessTokenExpirationDate": null,
"idToken": null, // here is the problem!
"refreshToken": null,
},
"displayName": "Danila Tsvetkov",
"email": "email#email",
"firstName": "Danila",
"hostedDomain": undefined,
"lastName": "Tsvetkov",
"serverAuthCode": null,
"uid": "uid",
}
At the same time Google OAuth API returns not only accessToken, but also idToken and refreshToken.
Everything else works fine, like authorization and sign in flow.
Maybe the problem is with serverAuthCode?
Tried to put webClientId, api stops working properly. Added SHA1 to google-services (more info), didn't help. Changing other params like "isOfflineEnabled" also doesn't do much.
Can you use this
const result = await Google.logInAsync({
androidClientId: "android id"
iosClientId: 'Ios Id',
scopes: ['profile', 'email'],
});
then
if (result.type === 'success') {
console.log(result.idToken);
//or
Alert.alert(result.idToken);
}
if (result.type === 'success') {
console.log(result.user.auth);
}
this is because we are using google-sign-in, instead of expo-google-app-auth
so in conclusion, use result.user.auth, but before that, your code should look something like this
signInAsync = async () => {
try {
await GoogleSignIn.askForPlayServicesAsync();
const result = await GoogleSignIn.signInAsync();
if (result.type === 'success') {
this.onSignIn(result.user.auth);
return result.user.auth;
}
} catch ({ message }) {
alert('login: Error:' + message);
}
};

How to use VueJS axios-oauth-client and google photos api?

I'm using vue cli and I try to get album list from my google photos account.
I'm using axios-oauth-client and I try to implement this code:
const axios = require('axios');
const oauth = require('axios-oauth-client');
const getAuthorizationCode = oauth.client(axios.create(), {
url: 'https://oauth.com/2.0/token',
grant_type: 'authorization_code',
client_id: 'foo',
client_secret: 'bar',
redirect_uri: '...',
code: '...',
scope: 'baz',
});
const auth = await getAuthorizationCode(); // => { "access_token": "...", "expires_in": 900, ... }
As described in here and I can't understand how do I get the authorization code aka code in this implementation.
I managed to do this call in postman but I'm unable to do it using axios.
Postman
My Code
async function getToken() {
const getAuthorizationCode = oauth.client(axios.create(), {
url: "https://oauth2.googleapis.com/token",
grant_type: "authorization_code",
client_id:
"**********.apps.googleusercontent.com",
client_secret: "***********",
redirect_uri: "http://localhost:8080/oauth2/callback",
code: "...",
scope: "https://www.googleapis.com/auth/photoslibrary.readonly"
});
const auth = await getAuthorizationCode(); // => { "access_token": "...", "expires_in": 900, ... }
console.log(auth);
}
getToken();
What am I doing wrong?
Thanks!
UPDATE
I still didn't manage to make it works but I found this answer which I will try to check.
UPDATE#2
Eventually I ended up using google documentation for Oauth2 using php and I took their git example as a base project.
In order to do it I also needed to use database to save the tokens and especially the refresh token which I use to refresh the access token every time I receive 401.

How to use OAuth2 with node.js

I would like to use #google-cloud client lib to insert data to BigQuery.
Since I have multiple clients and each has different IAM role I can't use a service account like this:
const bigquery = new BigQuery({
projectId: `myProject`,
keyFilename: '/Users/services/ssh/myProject-111.json'
});
rather I would like to use client-specific oauth2 like this:
const bigquery = new BigQuery({
projectId: `mydata-1470162410749`,
token: clientOauth2Token
});
I get this error
Error in the process: Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project. - Invalid Credentials
This is the full mocha test code I'm using:
import BigQuery from '#google-cloud/bigquery';
import {GoogApi} from "../apiManager" //Private code to get Token from client DB
if (!global._babelPolyfill) {
var a = require("babel-polyfill")
}
describe('Check routing', async () => {
it('Test stack ', async (done) => {
//Fetch client Auth from local Database
let apiManager = new GoogApi({query: {integrationTest: 'on'}}, {}, (err, httpResults) => {});
let clientAuth = await apiManager.getGoogleTokensByUserId(`user#company.con`);
//Replace the 2 value below with real values
const tableName = "myTest";
const dataset = "EVALUEX_DEV";
try {
const bigquery = new BigQuery({
projectId: `myProject`,
token: clientAuth.credentials.access_token
});
await bigquery.createDataset(dataset)
.then(
args => {
console.log(`Create dataset, result is: ${args}`)
})
.catch(err => {
console.log(`Error in the process: ${err.message}`)
})
} catch (err) {
console.log("err", err)
}
})
})
This is how my Token looks like when I Inspect it
{
"domain": null,
"_events": {},
"_eventsCount": 0,
"transporter": {},
"credentials": {
"access_token": "My Token",
"refresh_token": "my Refresh Token"
},
"certificateExpiry": null,
"refreshTokenPromises": [],
"_clientId": "my Client Id",
"_clientSecret": "My client secret",
"redirectUri": "https://s1dg0yjhih.execute-api.us-east-1.amazonaws.com/stage1/goog/saveToken",
"eagerRefreshThresholdMillis": 300000
}
The JSON object you shared is not an OAuth token, it looks like a OAuth2Client object from #google-auth-library.
An actual OAuth token is simply a string, like "ya29.ABC123ABC123_cG123ABCDETCETCETC".
That "token" is actually an OAuth2Client then you can fetch the token with the getAccessToken method. If it is just a plain JSON object, then you can get the credentials.access_token field, is the actual access token.
Note that access tokens expire. getAccessToken will get a new one if necessary, but just getting the access_token from the object will not, and can result in 403s after it expires.

Redirect_uri mismatch in fetch and gapi

working on connecting users to google, and we're trying to get their access and refresh tokens from the google api, and we're getting an issue exchanging the OAuth2 Code for tokens. Both sets of code have the same error.
I initialize the gapi client and fill in the information needed like so:
gapi.load('client:auth2', _ => {
gapi.client.init({
'apiKey': 'omitted for security',
clientId: 'omitted for security',
'scope': 'https://www.googleapis.com/auth/drive',
'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest']
}).then(_ => {
gapi.auth2.getAuthInstance().grantOfflineAccess().then(resp => {
if(resp.code){
gapi.client.request({
path: 'https://www.googleapis.com/oauth2/v4/token',
method: 'post',
params: {code: resp.code},
body: {
code: resp.code,
client_id: opts.clientId,
client_secret: 'omitted for security',
grant_type: 'authorization_code',
redirect_uri: 'omitted for security',
access_type: 'offline'
},
}).then((onfulfill, onreject, context) => {
console.log('fulfilled', onfulfill);
console.log('rejected: ', onreject);
console.log('context', context);
}).catch(err => console.error(err.body));
}
});
});
});
What I'm trying to do in the .then() is to call the token endpoint to exchange the code in the response for a refresh and access token to store in my back end and the user's local storage.
I get this error response from both versions of the code. (better, more reliable code is provided here.)
{ "error": "redirect_uri_mismatch", "error_description": "Bad
Request" }
I also have a backend setup stashed as a last resort that accepts the code from gapi.auth2.getAuthInstance().grantOfflineAccess() calls the token endpoint, and returns the access_token and refresh_token to the client.
This code is similar, but not quite. instead of using the google api library, I used fetch, and it works fine. (Fetch and XHR on the front end have the same issues as the gapi.client.request function....)
const gConfig = require('./basic.json');
const scopes = ['https://www.googleapis.com/auth/drive'];
const { client_id, client_secret, redirect_uris } = gConfig.web;
const authClient = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
app.post('/', (req, res) => {
const { code } = req.body;
console.log('Received Code From Request: ', code);
let data = { code , client_id, client_secret,redirect_uri: redirect_uris[0], grant_type: 'refresh_token'};
let encodedParams = Object.keys(data).map(k => encodeURIComponent(k) + '=' + encodeURIComponent(data[k])).join('&');
fetch(
`https://www.googleapis.com/oauth2/v4/token?code=${code}`,
{ method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: encodedParams }
).then((res) => {
console.log('called the api with fetch');
console.dir(res.json());
});
authClient.getToken(code, (err, token) => {
if (err) {
console.error(err);
res.status(500).json(err);
}
// console.dir(token);
console.log('TOKEN: =>', token);
res.json(token);
});
});
Is there anyone that's done this on the front end successfully?
You can't get a refresh token in a browser. Your example code would only work on a server. To do oauth at the client you should request "token" instead of "code".