How to authenticate as an User in Podio using NodeJS - javascript

I'm working on an integration between Slack and Podio. Up until now I've been authenticating as an APP in order to make some API calls. Now I find myself trying to use the Views API but I'm getting the following error message:
message: { error_parameters: {},
error_detail: null,
error_propagate: false,
request:
{ url: '<api url>',
query_string: '',
method: 'POST' },
error_description: 'Authentication as app is not allowed for this method',
error: 'forbidden' },
status: 403,
url: '<app url>',
name: 'PodioForbiddenError' }
The error_description makes me think that I need to authenticate as an user, in order to get the access to this API. This is how I'm authenticating right now:
const Podio = require('podio-js').api;
const podio = new Podio({
authType: 'app',
clientId: process.env.clientId,
clientSecret: process.env.clientSecret
});
I haven't been able to find an example of user authentication using node.js/javascript. Do I need to generate a new clientId and/or clientSecret? Can anyone provide a working example?
Thanks for your time!

To authenticate with app you need to provide the app id and app token. By providing client id and client secret you can get the podio client, then you need to authenticate the podio client with app credentials. like
podio.AuthenticateWithApp(appId, appToken);
you can get appid and app token from the developer tab of the app.

I ended up using podio.AuthenticateWithCredentials(userName, password);

Related

Possible to authenticate an AWS Cognito user via the API?

JavaScript/AWS here, although this is more of an AWS API question (since the JavaScript SDK just implements the API).
I'm looking at the AWS Cognito JavaScript SDK and trying to figure out how to programmatically authenticate a user given:
a username
a password
a user pool ID
But nothing obvious is jumping out at me. Is this not possible to do through their API/SDK? Do they force you to login from a web form?! Thanks in advance for any-and-all-steering!
I think there are couple of options that we can use here.
Let me provide examples with InitiateAuthCommand and AdminInitiateAuthCommand.
InitiateAuthCommand:
In order to user this, we should enable ALLOW_USER_PASSWORD_AUTH in the app client. This can be used in client-side authentication flow.
return new CognitoIdentityProviderClient({region: "<aws-region>"}).send(
new InitiateAuthCommand({
ClientId: "<the client id of the app>",
AuthFlow: AuthFlowType.USER_PASSWORD_AUTH,
AuthParameters: {
USERNAME: "<user#example.com>",
PASSWORD: "<password>",
},
})
)}
AdminInitiateAuthCommand:
In order to user this, we should enable ALLOW_ADMIN_USER_PASSWORD_AUTH in the app client. Also we have to configure the AWS credentials in the execution environment. So this can be used in Server-side authentication flow
return new CognitoIdentityProviderClient({region: "<aws-region>"}).send(
new AdminInitiateAuthCommand ({
ClientId: "<the client id of the app>",
AuthFlow: AuthFlowType.ADMIN_NO_SRP_AUTH,
UserPoolId:"<the user pool id>",
AuthParameters: {
USERNAME: "<user#example.com>",
PASSWORD: "<password>",
},
})
)}
NOTE: You can change the AuthFlow based on your requirement. Please read User pool authentication flow, InitiateAuthCommandInput.AuthFlow and AdminInitiateAuthCommandInput.AuthFlow for more details.

In JavaScript, how can we use the Microsoft Authentication Library to request a JWT token for a client connection with an an integration user?

We have a microservice, composed in JavaScript, which needs to consume a second microservice. The second microservice requires the consuming application to provide a JWT token which claims
"roles": [
"FooBar.Read"
],
for permission to use the service.
Rather than reinvent the wheel when calling Azure Active Directory to obtain and cache the token, we'd like to make use of the Microsoft Authentication Library node package.
I think we probably want to use the acquireTokenSilent() method of the ConfidentialClientApplication, but I'm not entirely clear how to create the request.
I've created this module:
import msal from '#azure/msal-node';
import {cachePlugin} from 'token-cache';
const confidentialClient = new msal.ConfidentialClientApplication({
auth: {
authority: `${process.env.AZURE_ACTIVE_DIRECTORY_AUTHORITY_URI}/${process.env.AZURE_ACTIVE_DIRECTORY_TENANT_ID}`,
clientId: process.env.AZURE_ACTIVE_DIRECTORY_CLIENT_ID,
clientSecret: process.env.AZURE_ACTIVE_DIRECTORY_CLIENT_SECRET,
knownAuthorities: [],
},
cache: {
cachePlugin,
},
system: {
loggerOptions: {
loggerCallback(loglevel, message) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: msal.LogLevel.Verbose,
},
},
});
const silentFlowRequest = {
account: {
tenantId: process.env.AZURE_ACTIVE_DIRECTORY_TENANT_ID,
username: process.env.AZURE_ACTIVE_DIRECTORY_USERNAME,
password: process.env.AZURE_ACTIVE_DIRECTORY_PASSWORD,
},
scopes: [process.env.AZURE_ACTIVE_DIRECTORY_EMPLOYEE_MANAGEMENT_SCOPE]
};
async function acquireToken() {
try {
return await confidentialClient.acquireTokenSilent(silentFlowRequest)
}
catch (error) {
console.error(error);
}
}
module.exports = {
acquireToken
};
However, I expect it to fail because Intell-J tells me:
Argument type {scopes: string[], account: {password: string, tenantId: string, username: string}} is not assignable to parameter type SilentFlowRequest
What is the correct way to do this?
Thanks for reaching out to us, please follow the doc - https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/AcquireTokenSilentAsync-using-a-cached-token#recommended-pattern-to-acquire-a-token .
hope this will help you.
You can use the MSAL's client credentials grant using a client secret in order to acquire tokens for your web API. We have a code sample with a fairly explanatory README here.
The client credentials grant first acquires a token (through ConfidentialClientApplicaiton.acquireTokenByClientCredentials) making a network request to AzureAD. Once the token is acquired, it is cached automatically by MSAL and subsequent calls will return the same token from the cache until it expires, at which point MSAL will refresh the token for you.
// Create msal application object
const confidentialClientApplication = new msal.ConfidentialClientApplication(
{
authOptions: {
clientId: "<ENTER_CLIENT_ID>",
authority: "https://login.microsoftonline.com/<ENTER_TENANT_ID>",
clientSecret: "<ENTER_CLIENT_SECRET>"
}
});
// Acquire tokens
function getClientCredentialsToken(confidentialClientApplication, scopes) {
// With client credentials flows permissions need to be granted in the portal by a tenant administrator.
// The scope is always in the format "<resource>/.default"
const clientCredentialRequest = {
scopes: scopes
};
return confidentialClientApplication
.acquireTokenByClientCredential(clientCredentialRequest)
.then((response) => {
// Handle response
}).catch((error) => {
// Handle error
});
}
Essentially, you create a client secret on the Azure Portal and then place it in your MSAL configuration. This secret is used in place of user credentials, allowing your application to authenticate with AzureAD and acquire tokens without any user interaction.

Why am I getting the error 'Can't generate token. Check your auth options' when using Nodemailer?

I see several similar questions regarding normal OATH. However, I decided to try nodemailers new
feature supporting gmail service accounts. I keep getting the same error over and over and no light on how to resolve it. Does anyone have any insight?
Step 1: I set up my service account from my project. Then I downloaded the key.json file.
Step 2: I went to GCP APIs and enabled gmail api for my project. I then verified that my new service account was in the list. (I don't want to post a pic because it contains sensitive information. But I triple checked that it was in the list of service accounts enabled for the gmail api.
Step 3: I wrote a little code.
return Promise.resolve()
.then(() => {
const mailTransport = nodemailer.createTransport({
service: 'gmail',
auth: {
type: 'OAuth2',
user: <service account email>,
serviceClient: <service account client>,
privateKey: <Private key> (including the \n at the end),
},
});
})
.then(() => {
const mailOptions = {
from: '"Support" support#myapp.com',
to: targetEmail,
subject: 'My Subject',
html: 'My super support email'
};
return mailTransport.sendMail(mailOptions);
})
.catch(err => {
console.error(err);
})
I print a nice wonderful error that says
Error { Error: Can't generate token. Check your auth options
at SMTPConnection._handleXOauth2Token (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:1697:27)
at SMTPConnection.login (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:540:22)
at XOAuth2.generateToken (/workspace/node_modules/nodemailer/lib/xoauth2/index.js:170:33)
at XOAuth2.getToken (/workspace/node_modules/nodemailer/lib/xoauth2/index.js:123:18)
at connection.connect (/workspace/node_modules/nodemailer/lib/smtp-transport/index.js:374:32)
at SMTPConnection.once (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:215:17)
at Object.onceWrapper (events.js:286:20)
at SMTPConnection.emit (events.js:198:13)
at SMTPConnection.EventEmitter.emit (domain.js:466:23)
at SMTPConnection._actionEHLO (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:1313:14) code: 'EAUTH', command: 'AUTH XOAUTH2' }
Does anyone have any idea what I am doing wrong?
Note: For a little more context. This runs inside of a firebase function.
I just had the same problem and I found a solution here:
https://levelup.gitconnected.com/multi-purposes-mailing-api-using-nodemailer-gmail-google-oauth-28de49118d77
As described in the tutorial you have to get your refresh token.
In your OAuth credentials in Google APIs Console provide https://developers.google.com/oauthplayground/ as redirection URI.
Go to https://developers.google.com/oauthplayground/ page.
In the right corner in settings menu select "Use your own OAuth credentials" and provide your credentials.
Then provide link https://mail.google.com in "Select & authorize APIs" section and click "Authorize APIs" button.
Finally exchange authorization code for tokens.
When you have the refresh token you can pass it in the configuration:
{
service: 'gmail',
auth: {
type: 'OAuth2',
user: USER_EMAIL_ADDRESS,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
refreshToken: REFRESH_TOKEN,
},
}
According to this answer the google's refresh token will not expire:
Do Google refresh tokens expire?
Best regards,
Piotr
In my case (and found in nodemailer's documentation), I wasn't pasting the entire private_key including the very beginning '-----BEGIN PRIVATE KEY-----\n...')

Creating a YouTube playlist with React using Google's API

I would like to create a YouTube playlist on a users account, but I have struggled to authenticate a POST to the YouTube v3 api.
I'll start by showing how far I have got with this problem.
YouTube API Documentation
The Youtube API Documentation provides details on creating a playlist, and has a working example in the API Explorer
I entered the following code into the request body:
{
"snippet":
{
"title":"Test Playlist"
}
}
This successfully created a playlist on my YouTube account with the same title. So from this I could tell that, a title was required within the body and it would require OAuth 2.0 authentication (an error is displayed if it is not enabled) using one the scopes: youtube, youtube.force-ssl, youtubepartner.
First attempt in react
The First thing I tried was similar to this:
fetch('/youtube/v3/playlists', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer' + api.youtube,
},
body: JSON.stringify({
"snippet":
{
"title":"Test"
}
})
}).then(response => response.json()).then(data => {
console.log(data)
})
api.youtube contains my YouTube api key.
Most of the formatting for this came from another API I have in the same program for getting data from spotify which works.
The response I got from this would say "Login failed" or "Authentication Error" (something along those lines)
Anyway, this is relevant because I know that my first hurdle is getting authentication.
Authentication
The YouTube API Documentation contains a guide titled Implementing OAuth 2.0 Authorization I followed the guide for client side web apps.
The first thing I noticed is that they are using a library, I found this on npm under googleapis and installed it.
When I tried to call this in React using
const {google} = require('googleapis');
I won't get deep into the error but react said "Can't convert undefined to object" and found an issue which said that googleapis is intended for server side not client side, I tried building the react app and putting it on herokuapp but got the same error. Someone else suggested using gapi-client on npm which is a node wrapper for googleapis.
The next thing I did was try the example on the npm page, which is very similar to the google example for configuring the client object. I have it so the import part and function are at the top of my app.js and then the gapi.load part activates after a button is pressed (this could be useless info but w/e)
import gapi from 'gapi-client';
//On load, called to load the auth2 library and API client library.
gapi.load('client:auth2', initClient);
function initClient() {
gapi.client.init({
discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/drive/v3/rest"],
clientId: 'YOUR_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/drive.metadata.readonly'
}).then(function () {
// do stuff with loaded APIs
console.log('it worked');
});
}
I copied my client ID in from the API Console and this is the exact response I got:
FireFox
Loading failed for the with source
“https://apis.google.com//scs/apps-static//js/k=oz.gapi.en.WcpMzqgmJZU.O/m=auth2,client/rt=j/sv=1/d=1/ed=1/am=AQ/rs=AGLTcCNsTS1p4dx0iMhlrwEpiaXw4iMjOg/cb=gapi.loaded_0”.
Chrome
GET
https://apis.google.com//scs/apps-static//js/k=oz.gapi.en.WcpMzqgmJZU.O/m=auth2,client/rt=j/sv=1/d=1/ed=1/am=AQ/rs=AGLTcCNsTS1p4dx0iMhlrwEpiaXw4iMjOg/cb=gapi.loaded_0
net::ERR_ABORTED 404
That's about as far as I got and I'm not sure what to do from here, so any help is much appreciated. I hope this didn't get too convoluted but I've tried to convey my problem as clearly as possible.
So I was able to authorize the YouTube API and create a playlist.
I have a backend hosted on localhost:8888 (doesn't matter just not what react is hosted on).
here is sample code for what I put in the server.js file (for the backend)
var express = require('express');
var app = express();
var passport = require('passport');
app.use(passport.initialize());
var YoutubeV3Strategy = require('passport-youtube-v3').Strategy;
passport.use(new YoutubeV3Strategy({
clientID: YOUR_CLIENT_ID,
clientSecret: YOUR_CLIENT_SECRET,
callbackURL: 'http://localhost:8888/redirect',
scope: ['https://www.googleapis.com/auth/youtube']
},
function (accessToken, refreshToken, profile, cb) {
var user = {
accessToken: accessToken,
refreshToken: refreshToken
};
return cb(null, user)
}
));
passport.serializeUser(function(user, cb) {
cb(null, user);
});
passport.deserializeUser(function(obj, cb) {
cb(null, obj);
});
app.get('/authenticate', passport.authenticate('youtube'))
app.get('/redirect', passport.authenticate('youtube', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('http://localhost:3000' + '?access_token=' + req.user.accessToken)
})
app.listen(8888)
This is using Passport.js to do oauth for me, lots of documentation can be found on the site.
In react I have it so a button will open localhost:8888/authenticate and then that will redirect back to my application. If you are using this you need to make sure that on your google API credentials you have the javascript origin as http://localhost:8888 and the redirect URI as http://localhost:8888/redirect and the correct scope and application type.
This is the function I use in my app.js (react) to make the POST
getAPIdata() {
let parsed = queryString.parse(window.location.search);
let accessToken = parsed.access_token
fetch('https://www.googleapis.com/youtube/v3/playlists?part=snippet', {
method: 'POST',
headers: {
'Content-type': 'application/json',
'Authorization': 'Bearer ' + accessToken,
},
body: JSON.stringify({
'snippet':
{
'title':this.state.inputTitle
}
})
}).then(response => response.json()).then(data => {
console.log(data)
window.alert('https://www.youtube.com/playlist?list=' + data.id)
})
}
I was actually mostly correct with the first attempt I just had the authorization incorrect.
Here's a couple sources that helped me make my solution:
Passport.js oauth tutorial
Googles OAuth 2.0 Playground
Passport.js Documentation
Passport.js facebook oauth example
Hopefully this is helpful to someone, You can use the same code i used in server.js to authenticate most services by just changing the strategy.
A live version of my application can be found here. In the console it shows the response from the POST request, this should help if you have any issues. I know the alert is bad ui but this wasn't the intended use.
Thanks for reading :)

Twitter Oauth javascript

I am trying to use andreassolberg's JSO OAuth library for implementing twitter signin via OAuth.My config is as follows
var config = {
providerID: "twitter",
client_id: "****",
redirect_uri: "http://localhost/jso/test/index.html",
authorization: "https://api.twitter.com/oauth/authorize",
scopes: { request: ["https://api.twitter.com/1.1/account/verify_credentials.json"]},
debug:true
};
The twitter response is like this,
"There is no request token for this page. That's the special key we
need from applications asking to use your Twitter account. Please go
back to the site or application that sent you here and try again; it
was probably just a mistake."

Categories

Resources