I am trying to use the GitHub Javascript API but am unable to authenticate using my API key. The API Docs say I can use:
{
username: 'my-username',
password: 'my-password'
// , token: 'or an optional oAuth token'
}
But I'd like to use my API Key instead, much like I can do with curl from the command line. (for example)
curl --user "$user:$api_key" --include --request DELETE "https://api.github.com/repos/$user/$repo/labels/enhancement"
I've tried using my API Key as the token but that doesn't work.
Is use of the API Key to access GitHub via the Github API wrapper not supported? That would be weird.
Okay so it turns out what I was calling my API Key is the same thing as the personal access token and I was just being confused because
import GitHub from 'github-api'
const gh = new GitHub({
token: 'MY-PERSONAL-ACCESS-TOKEN-OBTAINED-FROM-github.com/settings/tokens' // real token redacted obviously
})
const me = gh.getUser()
console.log('me', me)
was spitting out
me User {
__apiBase: 'https://api.github.com',
__auth:
{ token: '970818535b841883ff2735fe127d289032970389',
username: undefined,
password: undefined },
__AcceptHeader: 'v3',
__authorizationHeader: 'token MY-PERSONAL-ACCESS-TOKEN-OBTAINED-FROM-github.com/settings/tokens',
__user: undefined }
and I was interpreting __user: undefined to mean that the authentication was not working.
However if I actually try then adding
me.listNotifications().then(
notifications => console.log('notifications', notifications),
err => console.log('error', err)
).catch(err => console.log('fatal', err))
tadah it works.
If I throw in a rubbish token new GitHub doesn't complain (because presumably it's not actually going off to GitHub to do the auth at that point as I first thought), but the .listNotifications() does get rejected with a 401 error.
So, that's resolved my confusion.
Related
Context
I'm following Google's RTDNs guide on enabling Real-Time Developer Notifications. I've successfully created the topic and subscription and have received the push notifications sent to the API that I have created. I would now like to authenticate and validate these messages. For that, I'm following this guide on Authentication and Authorization. Their developer documentation here and here has a seemingly useful example.
The Issue
After following the resources outlined above, I get the following error:
Error: No pem found for envelope: {"typ":"JWT","alg":"HS256"}
Relevant Code
const authClient = new OAuth2Client();
// ...
app.post('/pubsub/authenticated-push', jsonBodyParser, async (req, res) => {
// Verify that the push request originates from Cloud Pub/Sub.
try {
// Get the Cloud Pub/Sub-generated JWT in the "Authorization" header.
const bearer = req.header('Authorization');
const [, token] = bearer.match(/Bearer (.*)/);
// Verify and decode the JWT.
// Note: For high volume push requests, it would save some network
// overhead if you verify the tokens offline by decoding them using
// Google's Public Cert; caching already seen tokens works best when
// a large volume of messages have prompted a single push server to
// handle them, in which case they would all share the same token for
// a limited time window.
// verifyIdToken is failing here with the `No pem found for envelope` error
const ticket = await authClient.verifyIdToken({
idToken: token,
audience: 'example.com',
});
// ...
} catch (e) {
res.status(400).send('Invalid token');
return;
}
res.status(200).send();
});
The Questions
From this, I'm assuming I need to have some public key.
Where do I get said public key?
Where do I put said public key so that the google client is initialized with it?
How can I generate an example JWT to test my endpoint?
Edits
I was able to find the source of this error in their code here:
if (!Object.prototype.hasOwnProperty.call(certs, envelope.kid)) {
// If this is not present, then there's no reason to attempt verification
throw new Error('No pem found for envelope: ' + JSON.stringify(envelope));
}
However, I've verified that the kid attribute does indeed exist in the decoded object:
{"alg":"RS256","kid":"7d680d8c70d44e947133cbd499ebc1a61c3d5abc","typ":"JWT"}
Turns out the kid was invalid and therefore threw the No pem found for envelope error. Once a valid kid was supplied, the error no longer persisted.
Description:
I have a frontend React client that is hosted on Firebase Hosting and a NodeJS Express API that is hosted on Google App Engine. The client needs to send a POST request to a NodeJS Express route, the request need to contain a variable called formid that holds the name of a firebase document. When both the server and client is run locally the formid variable gets sent to the API and it is not empty or undefined. But when the API is deployed and the request is sent to GAE instead I get this error:
UnhandledPromiseRejectionWarning: Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.
The error appears in the Google Cloud Platform Console. In left hand menu I go to; Operations > Logging > Logs Viewer. But I can also tail the logs to my local console with the command "gcloud app logs tail -s default".
Question: Why does the error appear only when the request is sent to GAE and not when I run them locally?
request.headers.form_id contains the name of the document stored in a collection (which is an autoID) in Google Firestore.
async function postFormQuestionHandler(request, response) {
let form_ref = db.collection("forms").doc(request.headers.form_id);
... other code
Express router that recieves the request, forwards it to postFormQuestionHandler function.
router.post("/question", (req, res) => {
postFormQuestionHandler(req, res);
});
Here is where the request firstly is being sent:
async addQuestionsToFormDb(idToken, fomrid, questionids) {
let result = await questionids.map(async (questionid) => {
let data = {
idToken: idToken,
form_id: formid,
question_id: questionid,
};
return await fetch(`${process.env.REACT_APP_API}/form/question`, {
method: 'POST',
mode: 'cors',
headers: data
});
}
From above code I have also tried using the Axios library but it also produces the same error on when the API is deployed to GAE. I have tried reading the documentation of both Axios (Github Axios Documentation) and Fetch (Firefox MDN web docs) but it have not helped me, am I missunderstanding something? Below is what I tried with Axios:
return await axios.post(`${process.env.REACT_APP_API}/form/question`, {}, {
headers: data,
}
);
Other information
Im using Express v4.17.1 and Node v10.19.0, I am also developing this with WSL 2 on Windows 10 2004.
your request.headers.form_id is either empty string or contain invalid character. I guess it contains slash /. Here is more info https://firebase.google.com/docs/firestore/quotas#collections_documents_and_fields
I'm having trouble using the reminder method to set a reminder using the Slack API.
https://api.slack.com/methods/reminders.add
I want to set a reminder for various people in our workspace. My understanding of the Slack API docs is that a workspace token is needed for permission, which I have created. See https://api.slack.com/docs/token-types#workspace
In POSTing the reminder request, I always get the error { ok: false, error: 'user_not_specified' }. I have specified a user as part of the payload, as well as text, time and the bearer token.
Strange, because the docs say that user is optional. Removing the user from the payload results in the same error.
I'm getting the same error in both Postman and in a simple snippet using the Node Slack API library:
const { WebClient} = require('#slack/client');
const token = process.env.SLACK_TOKEN || require('./.config').SLACK_API_TOKEN;
const web = new WebClient(token);
web.reminders.add({text: 'clean up duty', time: 'in 1 minute', user: 'U0FKQ3N94'})
.then((res) => {
console.log(res);
})
.catch(console.error);
Any idea what I am doing wrong?
I am currently trying to send a PushNotification to a Device Group using FCM with the help of Firebase Cloud Functions but once the notification is sent, it returns with code 200 but with failure :
SUCCESS response= {
multicast_id: 8834986220110966000,
success: 0,
failure: 1,
canonical_ids: 0,
results: [ { error: 'InvalidRegistration' } ]
}
Here is the code I am using to send this notification... what am I missing?
const options = {
method: 'POST',
uri: 'https://fcm.googleapis.com/fcm/send',
headers: {
'Authorization': 'key=' + serverKey,
},
body: {
to: groupId,
data: {
subject: message
},
notification: {
title: title,
body: body,
badge: 1,
},
content_available: true
},
json: true
};
return rqstProm(options)
.then((parsedBody) => {
console.log('SUCCESS response=', parsedBody);
})
.catch((err) => {
console.log('FAILED err=', err);
});
Where JSON values title, body, subject, message are String
In my case, I was sending notifications to topic ("topics/my-topic"). I was missing prepending / in the starting of topic so I was getting the same issue. SO topic should be /topics/my-topic.
May be this helps!!
There is an easier way to send a message to a device group from a Cloud Function. Use admin.messaging().sendToDeviceGroup(). Sample code and instructions are in this guide.
I think your current method is failing because there is something wrong with the group notification key provided in groupId. It should be the string key value that was returned when you created the device group. The error codes are listed in this table. For 200/InvalidRegistration it says:
Check the format of the registration token you pass to the server.
Make sure it matches the registration token the client app receives
from registering with Firebase Notifications. Do not truncate or add
additional characters.
I was losing my mind with this InvalidRegistration error.
Eventually the problem was that I was subscribing my device to "example" but sending the notification json to: "example".
But we actually need to send to "/topics/example"
2 hours of my life wasted..
A registration token is tied to a certain group of senders. When a client app registers for FCM, it must specify which senders are allowed to send messages. You should use one of those sender IDs when sending messages to the client app.
Al you need to do is add a http header 'project_id' with your sender id.
I was getting InvalidRegistration:
Basic meaning: you are using the wrong token. Why? This may happen when you a new registrationToken is given to you in onNewToken (docs), but for some reason you are using the old token. That could happen when:
You're using a different push notification library which remembers token (stores it somewhere locally) and you didn't update that library with the new token.
Your application (or other library dependencies) implements another FirebaseMessagingService, and they conflict. Only one service can accept (react to) to the action sent by the FirebaseMessaging Android library's when a new token is given to it. You can double check this by opening the AndroidManifest.xml in Android Studio and selecting the Merged Manifest tab at the bottom of the tab. You can also place debuggers in each Service from each library you use. You'll see that only one service's onNewToken gets called.
When they conflict, one doesn't get the correct token, and the FCM registration token that gets registered would be wrong. Sending a message to a wrong registration, gets you InvalidRegistration.
for me, it was a mistake that I was passing an Id from my models instead of the tokens of the users
InvalidRegistration simply means that the token is either invalid or expired. You can uninstall the app and then reinstall and get a new token and then try with that token. This will definitely solve your problem.
You can read more here.
I have trouble getting credentials in a browser script.
The authentication server returns cognito_identityId and cognito_token.
Then I set a Cookie:
$.cookie('cognito_identityId')
$.cookie('cognito_token')
I tried to get credentials in 4 ways on the browser, and all Failed:
CognitoIdentityCredentials
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxxxxxxxxxx'
IdentityId: $.cookie('cognito_identityId'),
Logins: {
'myauth': $.cookie('cognito_token')
}
});
// => Error: Missing required key 'IdentityId' in params
assumeRoleWithWebIdentity
var params = {
RoleArn: 'arn:aws:iam::xxxxxxxxxxxx:role/Cognito_xxxxxxxAuth_Role',
RoleSessionName: 'xxxxxxxxxxx',
WebIdentityToken: $.cookie('cognito_token'),
DurationSeconds: 900,
ProviderId: 'myauth'
};
var sts = new AWS.STS({apiVersion: '2011-06-15'});
sts.assumeRoleWithWebIdentity(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
// => AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity
PolicyDocument
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:xxxxxxxxxxxxx"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}
GetCredentialsForIdentity
var params = {
IdentityId: $.cookie('cognito_identityId'),
Logins: {
"myauth": $.cookie('oauth.io_token')
}
};
var cognitoidentity = new AWS.CognitoIdentity({apiVersion: '2014-06-30'});
cognitoidentity.getCredentialsForIdentity(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log(data); // successful response
}
});
// => InvalidParameterException: Please provide a valid public provider
WebIdentityCredentials
AWS.config.credentials = new AWS.WebIdentityCredentials({
RoleArn: 'arn:aws:iam::xxxxxxxx:role/Cognito_xxxxxxxxxxAuth_Role',
WebIdentityToken: $.cookie('cognito_token')
});
// => Error: There were 2 validation errors:
// * MissingRequiredParameter: Missing required key 'IdentityPoolId' in params
// * MissingRequiredParameter: Missing required key 'IdentityId' in params
Questions:
What am I doing wrong?
What is the correct way to use this?
Thank you.
Thank you for your kindness.
I tyied your advice, but did not change.
Error messages.
POST https://cognito-identity.us-east-1.amazonaws.com/ 400 (Bad Request)
POST https://cognito-identity.us-east-1.amazonaws.com/ 400 (Bad Request)
Error: Missing required key 'IdentityId' in params
at fail (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2163:37)
at validateStructure (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2084:14)
at validateMember (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2110:21)
at validate (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2059:10)
at Request.VALIDATE_PARAMETERS (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:800:32)
at Request.callListeners (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:3913:20)
at callNextListener (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:3903:12)
at chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:787:9
at finish (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:126:7)
at chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:142:9
There are source code below link.
https://github.com/bisque33/my-custom-dictionary
and server side is a AWS Lambda Function.
var aws = require('aws-sdk');
aws.config.region = 'us-east-1';
var cognitoidentity = new aws.CognitoIdentity();
var identityPoolId = 'us-east-1:0dccff0d-5fd7-4d14-b38f-d27204feaecc';
console.log('Loading function');
exports.handler = function(event, context) {
console.log('token: %s', event.token);
var params = {
IdentityPoolId: identityPoolId,
Logins: {
'oauth.io': event.token
}
};
cognitoidentity.getOpenIdTokenForDeveloperIdentity(params,function(err,data){
if(err){
console.log(err);
context.fail('Something went wrong');
}else{
context.succeed(data);
}
});
};
This program is Google-Chrome-Extension.
AWS Lambda Function returns token by getOpenIdTokenForDeveloperIdentity.
app/scripts/popup.js calls Lambda Function and set cookies.
app/scripts/background.js calls AWS.config.credentials.get, and returns error.
Am I using it wrong?
Update for Additional Information
Thank you for the additional information.
Error appears on 104 line on background.js
AWS.config.credentials.get(function(){
and 115 line on background.js
dataset.synchronize(
And, My explaination was not enough. Facebook authentication needs the domain(ex. http :// example.com). However, Google-Chrome-Ext does not have domain. It has a domain 'chrome-extension://xxxxxxxxxxxxxxxxxxxx'. Then, I use https://oauth.io. It proxies any authentication and accepts chrome-extension domain.
Popup.js does Facebook authentication through oauth.io sdk. It gets a facebook token, and gives to getOpenIdTokenForDeveloperIdentity. I think facebook token.substr(0,14) is unique. But, If it is wrong, I use another unique identifier(ex. email-address.)
Sorry, I was wrong. AWS.config.credentials.get gives an Error:
Error: Invalid login token.
And, dataset.synchronize shows this Error:
Error: Missing required key 'IdentityId' in params
The first approach you have, using CognitoIdentityCredentials, is most likely the best approach for you to take. I can't spot exactly what's causing the error for you but lets try a couple things:
When using Developer Authenticated Identities, you do need to specify the IdentityId when initializing CognitoIdentityCredentials. You need to get the IdentityId value from the call to GetOpenIdTokenForDeveloperIdentity. However, you shouldn't need to preserve the IdentityId value in a cookie as CognitoIdentityCredentials will cache the id by default in the browser's local storage.
As for your Logins map: It looks like you're trying to use Developer Authenticated Identities. With the JavaScript SDK, use the key 'cognito-identity.amazonaws.com' and make sure the value is the token returned from your backend's call to getOpenIdTokenForDeveloperIdentity.
If you continue to have problem using the CognitoIdentityCredentials approach, please reply here with some more info such as the exact method/code you're calling when you receive the error message, and the traced output (i.e. with console.log('%o',..)) of the params input just before your call to the CognitoIdentityCredentials constructor.
Update Based on Additional Information Provided
I still need to know exactly which line of code you receive the error on, but based on the information provided I think I can still help...
Based on what I see in background.js, it looks like you're trying to initialize CognitoIdentityCredentials using a Developer Authenticated Identities provider. This is where I'm guessing that you're receiving the error.
However, in Popup.js, it looks like you're trying to authenticate the user with Facebook. If you're authenticating your users with Facebook, you should just pass the facebook access token into your Logins map when using Cognito. Just use graph.facebook.com as the key in the Logins map and the access token from Facebook. More detail on how to do this is in the Facebook Integration topic of the Amazon Cognito developer guide.
Facebook vs Developer Authenticated Identities
We can get Developer Authenticated Identities to work for you, but in this case, it doesn't look like the right solution for you since you're not actually doing any additional authentication on the identity in your Lambda function and the unique user identifier that you're passing into the getOpenIdTokenForDeveloperIdentity operation appears to be the facebook token, which is not good by the way since the token itself will change between user sessions even for the same user. Usually a good unique identifier is an email address or a user id used by an internal system.
Facebook Login & Redirects
Since you're ultimately trying to use Facebook for login and Amazon Cognito has built-in integration for Facebook, the best thing for you to do is get an access token from Facebook and pass in the Facebook token to Cognito's login map directly. I'm not sure if this will work with Auth.io or not (I'm just not familiar with it), but as long as Auth.io gives your JavaScript code a bonefide facebook token and you add the same Facebook App ID to both Auth.io and Amazon Cognito's Console, it should work. However, you mentioned you want to use Auth.io to avoid Facebook doing a redirect to a landing page. I could be mistaken, but I'm pretty sure if you're using Facebook's JavaScript SDK you won't need a redirect page. You should only need the redirect page if you're doing Facebook's Manually Build a Login Flow.