How to include proxy configuration for npm module client-oauth2 - node.js

const ClientOAuth2 = require('client-oauth2');
const oauth2 = new ClientOAuth2({
clientId: 'clientId',
clientSecret: 'clientSecret',
accessTokenUri: 'https://fakeurl.com/v1/auth/token',
});
oauth2 .credentials.getToken().then(function (user) {
console.log(user);
}).catch(function (error) {
console.log(error);
});
Is there a way i can include proxy settings when requesting for a token given i am running this code inside a corporate network

I had a quick look and couldn't find an easy way to do it. Other than proxy features I noticed also that it is missing Open Id Connect features such as these:
Looking up metadata
Authorization Code Flow (PKCE)
Calls to the User Info Endpoint
REQUIREMENTS
Choosing a library for your apps is an important decision, and here are a few common things people usually look for:
Standards Based (works for any Authorization Server)
Certified as following the latest OAuth 2.1 and Open Id Connect recommendations
Supports HTTP proxying (highly useful to view OAuth messages when developing)
NODEJS SOLUTION
If you are using Node it might be worth considering the node openid-client library, which is the one I use. Here is some relevant code from an API of mine:
Looking up metadata - note that an agent can be supplied to support proxying
Setting the HTTP proxy - I use TunnelAgent.httpsOverHttp to proxy calls to HTTPS OAuth URLs
OAuth Operations - note that there are some custom classes that make these tasks easier

Related

How do we send post request with Kerberos authentication with axios on linux?

we are trying to call POST api to generate certificate for renewal of certification. However as per the 3rd party API reqirement, we need to validate Kerberos authentication. We have tried many thhings with no luck.
We are getting 401 unauthorized error when we are trying to run it.
Tech stack: Node.js, Javascript, Kerberos auth, Linux OS.
Code snippet:
const axios = require('axios');
const data = {
Request: "-----BEGIN CERTIFICATE REQUEST-----<csr key>-----END CERTIFICATE REQUEST-----",
CertificateTemplateName: "DBAPI1Y",
PrimaryEmail: "test#test.com"
};
axios.post('http://dummyurl.com/webapi/SubmitRequest', data, "Negotiate")
.then((res) => {
console.log(`Status: ${res.status}`);
console.log('Body: ', res.data);
}).catch((err) => {
console.error(err);
});
Tried this approach with no luck: How do I use Negotiate or Kerberos authentication with axios?
Can someone please help?
I was unable to find any traces of Negotiate support within axios. Your linked post says that in browsers it would work automatically, which is indeed true for any in-browser JavaScript (that uses Fetch or XMLHTTPRequest behind the scenes) – but the node CLI is a different world. When run through Node CLI, axios will use the HTTP client provided by Node, which doesn't do Kerberos.
It seems that you will need to implement this manually, by using the krb5 module to get a token, then telling axios to send it in the Authorization header – similar to Bearer tokens.
The following example seems to kind of work, although not very pretty – it cannot cope with '30x' redirects:
const axios = require("axios");
const krb5 = require("krb5");
// The service is "HTTP" (uppercase), regardless of the URL being http or https.
token = await krb5.spnego({hostbased_service: "HTTP#dummyurl.com"});
resp = await axios.post("https://dummyurl.com/webapi/SubmitRequest",
data,
{
headers: {
"Authorization": `Negotiate ${token}`,
},
// SPNEGO tokens are single-use, so if Axios tries to
// follow redirects, the 2nd request will be rejected
// as a "replay". So tell it to not even try.
maxRedirects: 0,
});
(I have no experience with writing "proper" Node.js code, especially async-based code, and while in theory it should be possible to use axios' transformRequest to dynamically get a new token for each request, I was unable to figure out how to do it within a sync function.)
In general, I would probably do the task in Python instead (which has well-maintained Kerberos integration using requests-gssapi or httpx-gssapi for Requests or httpx respectively).
Note that Kerberos doesn't ensure data integrity for HTTP, so you must still use HTTPS with it, otherwise someone could still simply MitM the requests.
Apart from the above approach suggested by #user1686, I have solved the problem using NTLM authentication. Specifically, I have used the httpntlm module.
By using the httpntlm package, we don't need to deal with kerberos packages as all the kerberos packages have many dependencies on node-gyp.
Thus, it's better to use some other solution apart from the kerberos related packages.
Note: This solution worked for me, but it will vary from use case to use case.

Best way to handle API calls from frontend

Okay, so atm i have a frontend application built with Nuxt JS using Axios to do requests to my REST API(separate).
If a user does a search on the website the API URL is visible in XMLHttprequests so everyone could use the API if they want to.
What is the best way of making it so that only users that search through my website gets access to the API and people that just directly to the URL gets denied. I suppose using some sort of token system, but what is the best way to do it? JWT? (Users never log in so there is no "authentication")
Thanks!
IMO, you CANNOT block other illegal clients accessing your
backend as you describe that the official client and other illegal have the same knowledge about your backend.
But you can make it harder for illegal clients to accessing your backend through some approach such as POST all requests, special keys in header, 30-minutes-changed token in header and server-side API throttling by client IP.
If the security of the search API is really important, authenticate it by login; if not, just let it go since it is not in your critical path. Let's focus on other important things.
I'm in the same "boat" and my current setup is actually in VueJs but before even come to StackOverflow I developed a way to actually, the frontend calls the server and then the server calls the API, so in the browser, you will only see calls to the server layer that, the only constraint is that the call must come from the same hostname.
backend is handled with expressJs and frontend with VueJs
// protect /api calls to only be originated from 'process.env.API_ALLOW_HOST'
app.use(api.allowOnlySameDomainRequests());
...
const allowHostname = process.env.API_ALLOW_HOST ||'localhost';
exports.api = {
...
allowOnlySameDomainRequests: (req, res, next) => {
if(req.url.startsWith('/api') && req.hostname === allowHostname) {
// an /api call, only if request is the same
return next();
} else if (!req.url.startsWith('/api')) {
// not an /api call
return next();
}
return res.redirect('/error?code=401');
},
...
};
In our case, we use Oauth2 (Google sign through passportJs) to log in the user, I always have a user id that was given by the OAuth2 successful redirect and that user id is passed to the API in a header, together with the apikey... in the server I check for that userid permissions and I allow or not the action to be executed.
But even I was trying to find something better. I've seen several javascript frontend apps using calls to their backend but they use Bearer tokens.
As a curious user, you would see the paths to all the API and how they are composed, but in my case, you only see calls to the expressJs backend, and only there I forward to the real API... I don't know if that's just "more work", but seemed a bit more "secure" to approach the problem this way.

Cross domain Sails.js + Socket.io authorization

I'm working in an application which delivers push content to a group of web applications hosted in different domains. I'm using Sails.js and Socket.io, and structured it like this:
The client script, running on each web application's client's browser, is something like:
socket.on('customEvent', function(message){
//do something with message on event trigger
}
And then, in the server, the event 'customEvent' is emitted when needed, and it works (e.g. on the onConnect event: sails.io.emit('customEvent',{message ...}).
But I'm facing a problem when it comes to handle authorization. The first approach I've tried is a cookie-based auth, as explained here (by changing the api/config/sockets.js function authorizeAttemptedSocketConnection), but it isn't a proper solution for production and it isn't supported in browsers with a more restrictive cookie policy (due to their default prohibition to third-party cookies).
My question is: how to implement a proper cross-browser and cross-domain authorization mechanism using sails.js, that can be supported in socket.io's authorization process?
======
More details:
I also tried adding a login with a well-known oauth provider (e.g. facebook), using this example as a base. I've got the Passport session, but I'm still unable to authenticate from the client script (it only works in pages hosted by my node app directly).
A JSONP request to obtain the session might be a solution, but it didn't work well in Safari. Plus I prefer the user to be authenticated in one of the web apps, rather than in my node application directly.
I believe your routes must handle CORS mate. Example:
'/auth/logout': {
controller: 'AuthController',
action: 'logout',
cors: '*'
},
Of course you can specify the list of ip your are accepting (and then replace the '*').
Worth mentionning that you must specify where socket.io has to connect to (front-end JS):
socket = io.connect(API.url);
For any common http GET/PUT/POST/DELETE, please ensure that your ajax envelope goes with the credentials (cookie). For example with angular:
$httpProvider.defaults.withCredentials = true
Let me know how it goes.

Sync contacts using Google Contacts API version 3.0 and NodeJS' Passport

I am using passport, and would like to use the Google Contacts API version 3.0 to sync Google contacts with my application (which would suddenly become 10 times more useful).
Has anybody done this? If so, do you have some example code? Is it even possible to use passport authentication to get it all working?
This comes in two parts, authorization, and then the actual request.
It is basically using OAuth2 protocol, where you redirect the client to google url with scopes(You must at least have https://www.google.com/m8/feeds in your scopes to be able to read and write contacts) and your client id/secret(get them by registering your app. Then google will redirect the user back with the access token on the URL.
You don't need to do this yourself, because there are different modules that already does this:
passport-google-oauth
This makes it easy and assuming you are already using passport, this probably what you want. It is written by the author of passportjs. Just follow the example in it for OAuth 2.0 strategy. Note that you need to you add the right scopes when you are calling passport.authenticate('google', ...). This module when it gets the token, it will get the user profile, so you have to have one of the 3 scopes below:
passport.authenticate('google', { scope: [ // One of the next three `auth` scopes are needed.
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/plus.login',
'https://www.google.com/m8/feeds'
] }),
googleapis
This is module is officially supported by google and created by google employees. You can use it to authenticate, but sadly it doesn't support gData, which contains google contacts. You can check the example to see how you can get the token. You only need the m8/feeds scope with this module, no need for the other ones if you don't want to get the user profile.
gdata-js
This is a non-popular non-maintaining module, but it is more lightweight than the previous two modules. It might need a little polishing out of the box. I suggest also reading the source for understanding the api right.
Once you got the tokens, then you go for the slightly easier part, making the requests and getting the data.
If you read the docs, it's actually very easy. For example to get all contacts(almost all, it's paginated), you need to make a GET request to this url:
https://www.google.com/m8/feeds/contacts/default/full?alt=json&oauth_token=THE_ACCESS_TOKEN
Again there are many modules that can help you in this.
google-contacts
node-gdata
gdata-js Read the source to understand it's api. It's pretty easy actually:
var client = require('gdata-js')(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET);
client.setToken({ access_token: accessToken, refresh_token: refreshToken });
client.getFeed('https://www.google.com/m8/feeds/contacts/default/full', function (err, result) { ... });
Google's official API for NodeJS doesn't support Contacts API, only the People API.
You can connect with Contacts API using the official googleapis library if you're already using it for other purposes by sending a request to the Contacts API after creating the auth client.
Given that you already have the access token of the user (e.g. if you generated it using Passport, here's the code:
const {google} = require("googleapis");
const authObj = new google.auth.OAuth2({
access_type: 'offline',
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
});
Refresh access token automatically before it expires
authObj.on('tokens', (tokens) => {
const access_token = tokens.access_token
if (tokens.refresh_token){
this.myTokens.refreshToken = tokens.refresh_token
// save refresh token in the database if it exists
}
this.myTokens.accessToken = tokens.access_token
// save new access token (tokens.access_token)
}
authObj.setCredentials({
access_token:this.myTokens.accessToken,
refresh_token:this.myTokens.refreshToken,
});
Make the request to Contacts API (Google uses Gaxios for making the requests to their APIs although it's not documented officially in googleapis, so just be aware that they might change remove/change the request call in the future without documenting it)
authObj.request({
headers:{
"GData-Version":3.0
},
params:{
"alt":"json",
//"q":"OPTIONAL SEARCH QUERY",
//"startindex":0
"orderby":"lastmodified",
"sortorder":"descending",
},
url: "https://www.google.com/m8/feeds/contacts/default/full"
}).then( response => {
console.log(response); // extracted contacts
});

Node.js and Twitter API 1.1

I had a small web app that was using the Twitter API 1.0 user_timeline function to quickly get a user's recent tweets without authentication. However, now every call requires oAuth which I'm terrible at. I know there's an application only authentication method, which is what I want since this is an automated app and not a user based one.
The application was built in node.js so a suggestion for a module that supports app-based oAuth would be great. The main thing is I don't have nor need a callback page, which most assume, since all I'm trying to do is get the last few tweets from a handful of specific Twitter accounts which the app tracks. Likewise any links to good oAuth educational resources or, better yet, Twitter 1.1 HTTP request walkthroughs would be much appreciated.
Thank you for your time.
Twitter API 1.1 allows only authenticated requests. But the good news is that the oAuth based authentication is not that difficult. To use it:
Generate the four oAuth keys you need. Go to https://dev.twitter.com/apps/new and register your app.
Install package ntwitter on your machine.
Configure the four keys in your app. See the package page on how to do it.
Construct request and get results. See this page on how to make requests.
I find oAuth to be easier and prefer this way.
The package EveryAuth does authentication pretty well, too. Also, ntwitter isn't being updated very regularly right now; I found mtwitter to be much better. I suck at explaining stuff, so I'll just show you how I did it:
var mtwitter = require('mtwitter');
var twit = new mtwitter({
consumer_key: { your app consumer key },
consumer_secret: { your app consumer secret },
access_token_key: { get this from oauth or everyauth or whatever },
access_token_secret: { get this from oauth or everyauth or whatever }
});
twit.get('/statuses/user_timeline', { include_entities: true },
function (err, data) {
if (err) {
console.log(err.toString());
}
else console.log(JSON.stringify(data));
});

Resources