Securing API Using HTTP Basic Auth - node.js

I'm looking into HTTP Basic Auth to secure my Nodejs API (using SSL too).
I'm wondering whether both a username and password are required with Basic Auth as I would just like to use a secret API key which would serve as a username. Resources I have read appear to suggest that both are required but Stripe's docs appear to suggest that just a username is sufficient:
https://stripe.com/docs/api#authentication
"Authentication to the API occurs via HTTP Basic Auth. Provide your API key as the basic auth username. You do not need to provide a password"

You can use the basicAuth middleware in express to do this http://expressjs.com/api.html#basicAuth. Just set the username(s) to the API key and the password(s) to ' ' (empty string, not double quote).

You can also use http-auth module for HTTP Basic/Digest authentication.
// Authentication module.
var auth = require('http-auth');
var basic = auth.basic({
realm: "Simon Area.",
file: __dirname + "/../data/users.htpasswd" // gevorg:gpass, Sarah:testpass ...
});
// Creating new HTTP server.
http.createServer(basic, function(req, res) {
res.end("Welcome to private area - " + req.user + "!");
}).listen(1337);

Related

Delegate authentication token from react app to express app with OpenID and passportjs

I am using the OpenID client to authenticate the user, what I would like to do is call a protected route on an express API.
I am trying to share the authorization cookie obtained with the react app with OpenID, and the xenter image description here
I tried:
simply passport.authenticate(), with the openID strategy, but does redirection which isnt necessary
Not sure if this is the correct way but, this is how I kinda did it:
const user = await auth0Client.getUser();
// Attach token
const accessToken = await auth0Client.getTokenSilently();
axios.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
Then I just used the passport JWT strategy combined with jwks-rsa library to obtain the secret.

express-session vs passport.js?

I am currently implementing email-password login functionality for a website using just express-session. Everywhere I look I see people using passport.js to authenticate requests. The below code is working for me.
app.post("/signup", function(req, res) {
var user = new userModel(req.body);
user.save();
req.session.userid = user.id; // I use this id to authenticate
}
Do I have any reason to use passport?
In NodeJS, you can authenticate in 2 ways:
Session-Based authentication
Token-Based authentication
Passport is a token-based authentication system. It uses JSON web token i.e jwt.
In your case, as you are using session-based authentication you need not use passport

Authenticate static pages with passportjs and express

I am using passportjs to authenticate a simple web app. I am able to store the session and check whether the user exists using req.user on pages that are making calls to my node server. However, there I also have static pages that are not making calls -- if someone were to guess the URL of these pages, they'd be able to get into the app without authentication. How can I authenticate these static pages through the server?
You could introduce authentication for static files by adding auth middleware to your route.
var jwt = require('express-jwt');
var auth = jwt({secret: 'SECRET', userProperty: 'payload'});
app.use(auth, express.static('public'));
If you dont use jwt, a custom function can be passed instead of auth.
app.use('/pagecontainer', yourAuthFunction, express.static(__dirname + '/public/pagecontainer'));
Define a static route to access the folder where your pages are in, and add the passport authentication (yourAuthFunction) middle-ware function to authenticate requests coming to that folder.

Securing HTTP endpoint using service api

Below is the code, where I am trying to authenticate using third party providers. My authentication call is a service api which is running in different servers. How can authenticate users in my code
//app.js
app.use(passport.initialize());
// Create our Express router
var router = express.Router();
router.route('/test')
.get(**<first authenticate user using service api http://localhost:1000/authenticate>**, serviceController.getData);
app.listen(2000);
//authController.js
var app = express();
var router = express.Router();
router.post("/authenticate",function(req,res){
//Using third party providers like LDAP or Facebook using Passport
res.send("User authenticated");//Token will be send
});
app.listen(1000);
//authController.js - as function call it is working
var passport = require('passport');
var BasicStrategy = require('passport-http').BasicStrategy;
passport.use(new BasicStrategy(
function (username, password, callback) {
// Success
//return callback(null, true);
}
));
exports.isAuthenticated = passport.authenticate('basic', { session: false });
Is it possible to secure my api http://localhost:2000/test using LDAP or Facebook authentication. I am looking for something similar to SSO.
Expected result
When I hit http://localhost:2000/test, a request must be made to LDAP or facebook server running in http://localhost:1000/ to validate user and send the response from "User authenticated".
Any help on this will be really helpful.
there are couple of possibilities to achieve that using node.js
Passport Facebook; https://github.com/jaredhanson/passport-facebook
LDAP for node.js; http://ldapjs.org/
Passport provides plenty of different possibilities to login: twitter, google, facebook, linkedin, instagram. They are pretty easy to implement as well.
Check it here: http://passportjs.org/docs

What authentication strategy to use? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Recently I have been reading up on OAuth2, OpenID Connect etc. But still very lost at what to use when and how to implement it. I am thinking of using NodeJS for now.
Lets say I want to create a blog service. This service will expose API's for clients to use. "Clients" include an admin CMS. I am thinking it will be nice to decouple my server and client (UI). I can change the UI without touching the server. These clients are likely going to be single page web applications.
Ok 1st question: In this example, should I be using OAuth2? Why? Isit just because I am authorizing the admin app to access by blog?
Since its SPA's, I think the right strategy is OAuth2 Implicit Flow?
For each app, eg. admin cms, I will have to generate an AppID which is passed to the auth server. No app secret is required correct?
Isit possible to use google login in this case (instead of username/password)? Does OpenID connect do this?
How do I implement all these in NodeJS? I see https://github.com/jaredhanson/oauth2orize, but I do not see how to implement the implicit flow.
I do see an unofficial example https://github.com/reneweb/oauth2orize_implicit_example/blob/master/app.js, but what I am thinking is why is sessions required? I thought one of the goals of tokens is so that server can be stateless?
I am also wondering, when should I use API key/secret authentication?
Let's examine your questions
Should I be using OAuth2? Why?
A: Well, as today the old OpenId 2 authentication protocol has been marked as obsolete (November 2014) and OpenId Connect is an identity layer built on top of OAuth2 so the real question is if is important for you and your business to know and verify the identity of your users (the authentication part). If the answer is "yes" then go for OpenId Connect otherwise you can choose any of the two, the one you feel more comfortable with.
Since its SPA's, I think the right strategy is OAuth2 Implicit Flow?
A: Not really. You can implement any strategy when using a SPA, some takes more work than others and greatly depends on what are you trying to accomplish. The implicit flow is the simplest but it does not authenticate your users since an access token is issued directly.
When issuing an access token during the implicit grant flow, the authorization server does not authenticate the client. In some cases, the client identity can be verified via the redirection URI used to deliver the access token to the client.
I would not recommend this flow for your app (or any app that needs a decent level of security1).
If you want to keep it simple you should use Resource Owner Grant flow with an username and password but again there is nothing that prevents you of implementing the Authorization Code Grant flow especially if you want to allow third parties apps to use your service (which in my opinion is a winning strategy) and it will be relatively more secure than the others since it requires explicit consent from the user.
For each app, eg. admin cms, I will have to generate an AppID which is passed to the auth server. No app secret is required correct?
A: Yes that is correct but the client_secret can be used to add an extra layer of security to the token endpoint in the resource owner flow when you can't use Basic authentication, this is not required in any other flow.2 3
The authorization server MUST:
require client authentication for confidential clients or for any
client that was issued client credentials (or with other
authentication requirements),
authenticate the client if client authentication is included, and
validate the resource owner password credentials using its
existing password validation algorithm.
and
Alternatively, the authorization server MAY support including the client credentials in the request-body (...) Including the client credentials in the request-body using the two parameters is NOT RECOMMENDED and SHOULD be limited to clients unable to directly utilize the HTTP Basic authentication scheme (or other password-based HTTP authentication schemes)
Is it possible to use google login in this case (instead of username/password)? Does OpenID connect do this?
A: Yes, is possible to use google login in which case you are just delegating the authentication and authorization job to the google servers. One of the benefits of working with an authorization server is the ability to have a single login to access other resources without having to create a local account for each of the resources you want to access.
How do I implement all these in NodeJS?
Well you started with the right foot. Using oaut2horize is the most simple way to implement an authorization server to issue tokens. All other libraries I tested were too complicated of use and integrate with node and express (disclaimer: this is just my opinion). OAuthorize plays nicely with passport.js(both from the same author) which is a great framework to enforce the authentication and authorization with over 300+ strategies like google, facebook, github, etc. You can easily integrate google using passport-google(obsolete), passport-google-oauth and passport-google-plus.
Let's go for the example
storage.js
// An array to store our clients. You should likely store this in a
// in-memory storage mechanism like Redis
// you should generate one of this for any of your api consumers
var clients = [
{id: 'as34sHWs34'}
// can include additional info like:
// client_secret or password
// redirect uri from which client calls are expected to originate
];
// An array to store our tokens. Like the clients this should go in a memory storage
var tokens = [];
// Authorization codes storage. Those will be exchanged for tokens at the end of the flow.
// Should be persisted in memory as well for fast access.
var codes = [];
module.exports = {
clients: clients,
tokens: tokens,
codes: codes
};
oauth.js
// Sample implementation of Authorization Code Grant
var oauth2orize = require('oauth2orize');
var _ = require('lodash');
var storage = require('./storage');
// Create an authorization server
var server = oauth2orize.createServer();
// multiple http request responses will be used in the authorization process
// so we need to store the client_id in the session
// to later restore it from storage using only the id
server.serializeClient(function (client, done) {
// return no error so the flow can continue and pass the client_id.
return done(null, client.id);
});
// here we restore from storage the client serialized in the session
// to continue negotiation
server.deserializeClient(function (id, done) {
// return no error and pass a full client from the serialized client_id
return done(null, _.find(clients, {id: id}));
});
// this is the logic that will handle step A of oauth 2 flow
// this function will be invoked when the client try to access the authorization endpoint
server.grant(oauth2orize.grant.code(function (client, redirectURI, user, ares, done) {
// you should generate this code any way you want but following the spec
// https://www.rfc-editor.org/rfc/rfc6749#appendix-A.11
var generatedGrantCode = uid(16);
// this is the data we store in memory to use in comparisons later in the flow
var authCode = {code: generatedGrantCode, client_id: client.id, uri: redirectURI, user_id: user.id};
// store the code in memory for later retrieval
codes.push(authCode);
// and invoke the callback with the code to send it to the client
// this is where step B of the oauth2 flow takes place.
// to deny access invoke an error with done(error);
// to grant access invoke with done(null, code);
done(null, generatedGrantCode);
}));
// Step C is initiated by the user-agent(eg. the browser)
// This is step D and E of the oauth2 flow
// where we exchange a code for a token
server.exchange(oauth2orize.exchange.code(function (client, code, redirectURI, done) {
var authCode = _.find(codes, {code: code});
// if the code presented is not found return an error or false to deny access
if (!authCode) {
return done(false);
}
// if the client_id from the current request is not the same that the previous to obtain the code
// return false to deny access
if (client.id !== authCode.client_id) {
return done(null, false);
}
// if the uris from step C and E are not the same deny access
if (redirectURI !== authCode.uri) {
return done(null, false);
}
// generate a new token
var generatedTokenCode = uid(256);
var token = {token: generatedTokenCode, user_id: authCode.user_id, client_id: authCode.client_id};
tokens.push(token);
// end the flow in the server by returning a token to the client
done(null, token);
}));
// Sample utility function to generate tokens and grant codes.
// Taken from oauth2orize samples
function uid(len) {
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var buf = []
, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
, charlen = chars.length;
for (var i = 0; i < len; ++i) {
buf.push(chars[getRandomInt(0, charlen - 1)]);
}
return buf.join('');
}
module.exports = server;
app.js
var express = require('express');
var passport = require('passport');
var AuthorizationError = require('oauth2orize').AuthorizationError;
var login = require('connect-ensure-login');
var storage = require('./storage');
var _ = require('lodash');
app = express();
var server = require('./oauthserver');
// ... all the standard express configuration
app.use(express.session({ secret: 'secret code' }));
app.use(passport.initialize());
app.use(passport.session());
app.get('/oauth/authorize',
login.ensureLoggedIn(),
server.authorization(function(clientID, redirectURI, done) {
var client = _.find(storage.clients, {id: clientID});
if (client) {
return done(null, client, redirectURI);
} else {
return done(new AuthorizationError('Access denied'));
}
}),
function(req, res){
res.render('dialog', { transactionID: req.oauth2.transactionID, user: req.user, client: req.oauth2.client });
});
app.post('/oauth/authorize/decision',
login.ensureLoggedIn(),
server.decision()
);
app.post('/oauth/token',
passport.authenticate(['basic', 'oauth2-client-password'], { session: false }),
server.token(),
server.errorHandler()
);
(...) but what I am thinking is why is sessions required? I thought one of the goals of tokens is so that server can be stateless?
When a client redirects a user to user authorization endpoint, an authorization transaction is initiated. To complete the transaction, the user must authenticate and approve the authorization request. Because this may involve multiple HTTP request/response exchanges, the transaction is stored in the session.
Well yes, but the session is used for the token negotiation process. Later you enforce authorization sending the token in an Authorization header to authorize each request using the obtained token.
In my experience, OAuth2 is the standard way of securing APIs. I'd recommend using OpenID Connect though as it adds authentication to OAuth2's otherwise authorization-based spec. You can also get Single-Sign-On between your "clients".
Since its SPA's, I think the right strategy is OAuth2 Implicit Flow?
De-coupling your clients and servers is a nice concept (and I'd generally do the same too) however, I'd recommend the authorization code flow instead as it doesn't expose the token to the browser. Read http://alexbilbie.com/2014/11/oauth-and-javascript/. Use a thin server-side proxy instead to add the tokens to the request. Still, I generally avoid using any server-generated code on the client (like JSPs in java or erb/haml in rails) since it couples the client to the server too much.
For each app, eg. admin cms, I will have to generate an AppID which is passed to the auth server. No app secret is required correct?
You'll need a client ID for implicit flow. If you use authorization code flow (recommended), you'll need both an ID and secret but the secret will be kept in the thin server-side proxy rather than a client-side only app (since it can't be secret in that case)
Is it possible to use google login in this case (instead of username/password)? Does OpenID connect do this?
Yes. Google uses openid connect
How do I implement all these in NodeJS? I see https://github.com/jaredhanson/oauth2orize, but I do not see how to implement the implicit flow.
A nice thing about openid connect is that (if you use another provider like google), you don't have to implement the provider yourself and you'll only need to write client code (and/or utilize client libaries). See http://openid.net/developers/libraries/ for different certified implementations. See https://www.npmjs.com/package/passport-openidconnect for nodejs.

Resources