thanks in advance for any assistance that can be provided. My goal is to use OAuth2 to get users’ step data from the Google Fit API. I am able to authenticate using Expo's expo-app-auth package, and receive an accessToken, but, when I try to read from the Fit API, I get an error that the authentication credential is missing.
Relevant Code:
let config = {
issuer: 'https://accounts.google.com',
scopes: ['openid', 'profile', 'https://www.googleapis.com/auth/fitness.activity.read'],
/* This is the CLIENT_ID generated from a Firebase project */
clientId: 'xxx.apps.googleusercontent.com',
};
let authState = await AppAuth.authAsync(config); // this returns an idToken, accessToken, list of scopes configured, including the fitness.activity.read
const url = 'https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate';
const today = new Date().getTime();
const past = today - (5 * 24 * 60 * 60 * 100);
const body = {
"aggregateBy": [{
"dataTypeName": "com.google.step_count.delta",
"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"
}],
"bucketByTime": { "durationMillis": 86400000 },
"startTimeMillis": today,
"endTimeMillis": past
}
const header = {
'Content-Type': 'application/json',
'Authorization': `BEARER ${authState.accessToken}`
}
const req = await fetch(url, {
method: 'POST',
headers: header,
body: JSON.stringify(body)
});
const resp = await req.json();
/*
Object {
"error": Object {
"code": 401,
"errors": Array [
Object {
"domain": "global",
"location": "Authorization",
"locationType": "header",
"message": "Login Required.",
"reason": "required",
},
],
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED",
},
}
*/
I am able to produce this issue using a built apk on a real device. For the standalone build, I am using an OAuth2 clientId from Google Console as clientId in the config, and the Fitness API is enabled.
Does anyone know what I might be doing incorrectly?
Related
I want to use TikTok API with oAuth mechanism.
And my controller for start oAuth Mechanism Like that:
logger.info('Handle request from Tiktok Auth')
const csrfState = Math.random().toString(36).substring(2)
res.cookie('csrfState', csrfState, { maxAge: 60000 })
let url = 'https://open-api.tiktok.com/platform/oauth/connect/'
url += `?client_key=${process.env.TIKTOK_CLIENT_KEY}`
url += '&scope=user.info.basic,video.list'
url += '&response_type=code'
url += '&redirect_uri=https://www.helloworld.com/tiktok/callback/'
url += `&state=${csrfState}`
res.redirect(url)
And my callback code snipped like that:
const config = {
method: 'post',
url: 'https://open-api.tiktok.com/oauth/access_token/',
params: {
client_key: process.env.TIKTOK_CLIENT_KEY,
client_secret: process.env.FACEBOOK_CLIENT_SECRET,
grant_type: 'authorization_code',
code,
},
headers: {},
}
return axios(config)
But, as a response I received this response with status:200 :
{
"data": {
"captcha": "",
"desc_url": "",
"description": "",
"error_code": 10013
},
"message": "error"
}
I researched status codes for TikTok API, but I cannot find anything.
What does the "10013" error code mean?
Why I'm getting this error? How can I solve this?
Please Help!
You can find the TikTok Error Codes here.
https://developers.tiktok.com/doc/getting-started-android-handling-errors/
Error 10013: Client key or client secret error.
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.
I've used this to setup auth in strapi and nuxt:
Auth with Strapi and Nuxt
I'm currently trying to retrieve the items specific to a authenticated user (already checked out this strapi - restrict user to fetch only data related to him). To do this I created a custom route in Strapi (/api/routine/config/routes.json):
{
"method": "GET",
"path": "/routines/me",
"handler": "Routine.me",
"config": {
"policies": []
}
}
and a custom controller (/api/controllers/Routine.js):
module.exports = {
me: async (ctx) => {
const user = ctx.state.user;
if (!user) {
return ctx.badRequest(null, [{ messages: [{ id: 'No authorization header was found' }] }]);
}
const data = await strapi.services.routine.find({user:user.id});
if(!data){
return ctx.notFound();
}
ctx.send(data);
},
};
I already gave permission through Strapi admin for authenticated users to access 'me'. When I hit the endpoint from Nuxt:
const routines = await axios.get(http://localhost:1337/routines/me)
I get this error:
GET http://localhost:1337/routines/me 404 (Not Found)
Why is the custom route not found? Am I using the wrong endpoint?
Maybe you have already solved it, but it seems like you forget to send the authentication header with the request.
const routines = await axios.get(
'http://localhost:1337/routines/me', {
headers: {
Authorization:
this.$auth.getToken('local'),
},
}
It was a fault in my Strapi routes config. Answer was provided through the amazingly helpful Strapi forums:
403 forbidden when calling custom controller from Nuxt
Here is the problem:
{
"method": "GET",
"path": "/routines/:id",
"handler": "routine.findOne",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/routines/me",
"handler": "routine.me",
"config": {
"policies": []
}
So basically you are hitting the first route right now and it assumes that
me is actually an :id. Koa is making the verifications with regex so in this case it takes the first matched route. Move the route with /me above that one with /:id
I am trying to create an automated JIRA ticket using the REST API but I keep getting a 405 error.
I am using the examples here: https://developer.atlassian.com/server/jira/platform/jira-rest-api-examples/
Also, when I visit the post URL directly I do not get any errors so I doubt it is a server issue. Any ideas?
var Client = require('node-rest-client').Client;
client = new Client();
// Provide user credentials, which will be used to log in to Jira.
var loginArgs = {
data: {
"username": "user",
"password": "pass"
},
headers: {
"Content-Type": "application/json"
}
};
client.post("https://jira.mydomain.com/rest/auth/1/session", loginArgs, function(data, response) {
if (response.statusCode == 200) {
//console.log('succesfully logged in, session:', data.session);
var session = data.session;
// Get the session information and store it in a cookie in the header
var args = {
headers: {
// Set the cookie from the session information
cookie: session.name + '=' + session.value,
"Content-Type": "application/json"
},
data: {
// I copied this from the tutorial
"fields": {
"project": {
"key": "REQ"
},
"summary": "REST ye merry gentlemen.",
"description": "Creating of an issue using project keys and issue type names using the REST API",
"issuetype": {
"name": "Request"
}
}
}
};
// Make the request return the search results, passing the header information including the cookie.
client.post("https://jira.mydomain.com/rest/api/2/issue/createmeta", args, function(searchResult, response) {
console.log('status code:', response.statusCode);
console.log('search result:', searchResult);
});
} else {
throw "Login failed :(";
}
});
I am expecting the Jira ticket of type REQ to be created with the details I added in the fields section.
I believe you are using the incorrect REST API; what you're currently doing is doing a POST to Get create issue meta which requires a GET method, hence, you're getting a 405. If you want to create an issue, kindly use Create issue (POST /rest/api/2/issue) instead.
The same request including the access token is working with CURL and Postman.
The code from Postman (masked credentials and ids) is included.
var http = require("https");
var options = {
"method": "GET",
"hostname": [
"3",
"basecampapi",
"com"
],
"path": [
"<MASKED ACCOUNT ID>",
"my",
"profile.json"
],
"headers": {
"Authorization": "Bearer <MASKED AUTH TOKEN>",
"Cache-Control": "no-cache",
"Postman-Token": "92fc7993-57aa-47f7-aaae-44925dd37f3e"
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.end();
Use NodeJS Request instead of NodeJS Native when creating code from a Postman request.