What authentication strategy to use?

I recently read OAuth2, OpenID Connect, etc. But I still really lost what to use, when and how to implement it. At the moment, I am thinking about using NodeJS.

Suppose I want to create a blog service. This service will provide APIs for use by customers. "Clients" include administrative CMS. I think it will be nice to separate my server and client (UI). I can change the interface without touching the server. These clients are likely to be single page web applications.

OK 1st question: Should OAuth2 be used in this example? What for? Isit just because I authorize the admin application to access the blog?

Since my SPA, I think the right strategy is OAuth2 Implicit Flow?

For each application, for example. admin cms, I will have to generate the AppID, which is passed to the auth server. No application secret required?

Is it possible to use Isit in this case (instead of username / password)? Does OpenID connect?

How can I implement all this in NodeJS? I see https://github.com/jaredhanson/oauth2orize , but I do not see how to implement an implicit stream.

I see an unofficial example https://github.com/reneweb/oauth2orize_implicit_example/blob/master/app.js , but I think, why do I need sessions? I thought one of the goals of the tokens is that a server can be stateless?

I am also wondering when to use the API key / secret authentication?

+6
source share
2 answers

Let's look at your questions.

  • Should I use OAuth2? Why?

    A: Well, since the old OpenId 2 authentication protocol was marked obsolete today (November 2014) and OpenId Connect is an authentication layer built on top of OAuth2, so the real question is whether it is important for you and your business to know and verify the identity of your users (part of authentication). If the answer is yes, then go to OpenId Connect, otherwise you can choose either of the two, the one with which you will be comfortable.

  • Since my SPA, I think the right strategy is OAuth2 Implicit Flow?

    A: Not really. You can implement any strategy when using SPA, some of them take more work than others, and are very dependent on what you are trying to accomplish. An implicit stream is the simplest, but it does not authenticate your users , since the access token is issued directly.

    When issuing an access token during an implicit grant flow, the authorization server does not authenticate the client. In some cases, the client identifier can be verified using the redirect URI used to deliver the access token to the client.

    I would not recommend this thread for your application (or any application that needs a decent level of security 1 ).

    If you want to keep it simple, you should use the Resource Owner Grant with a username and password, but again there is nothing that would prevent you from implementing the Authorization code , especially if you want to allow third-party applications to use your service (which, in my opinion, is a winning strategy), and it will be relatively more secure than others, as this requires explicit user consent.

  • For each application, for example. admin cms, I will have to generate the AppID, which is passed to the auth server. No application secret required?

    A: Yes, that’s correct, but client_secret can be used to add an additional level of security to the endpoint of the token in the resource owner’s stream, if you cannot use basic authentication, this is not required in any other stream. 2 3

    The authorization server MUST:

    • client authentication is required for confidential clients or for any client to whom client credentials have been issued (or with other authentication requirements),

    • authenticate the client if client authentication is enabled, and

    • Verify the password credentials of the resource owner using its existing password verification algorithm.

    and

    Alternatively, the authorization server MAY support, including client credentials in the request body (...) Including client credentials in the request body using two parameters is NOT RECOMMENDED and MUST be limited to clients that cannot directly use the basic HTTP 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 include a connection?

    A: Yes, you can use the google login, in which case you simply delegate the authentication and authorization task to google servers. One of the advantages of working with an authorization server is the ability to have one login to access other resources without having to create a local account for each of the resources that you want to access.

  • How to implement all this in NodeJS?

    Well, you started with the right foot. Using oaut2horize is the easiest way to implement an authorization server to issue tokens. All other libraries that I tested were too complicated to use and integrate with node and express (disclaimer: this is just my opinion). OAuthorize plays great with passport.js (like the same author), which is an excellent basis for providing authentication and authorization with more than 300+ strategies such as google, facebook, github, etc. You can easily integrate Google using passport-google (deprecated), passport-google-oauth and passport-google-plus .

    Let’s let go for an 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 // http://tools.ietf.org/html/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 I think, why do we need sessions? I thought one of the goals of the tokens is that the server can be stateless?

    When the client redirects the user to the user's authorization endpoint, an authorization transaction is initiated. To complete the transaction, the user must authenticate and approve the authorization request. Since this may include multiple HTTP request / response exchanges, the transaction is saved in the session.

    Well, yes, but the session is used for the token negotiation process. Later, you perform authorization by sending a token in the authorization header to authorize each request using the received token.

+13
source

In my experience, OAuth2 is the standard way to protect an API. I would recommend using OpenID Connect, although it adds authentication to OAuth2, as opposed to a specification based on authorization. You can also get Single-Sign-On between your “customers”.

Since my SPA, I think the right strategy is OAuth2 Implicit Flow?

Removing your clients and servers is a good concept (and, as a rule, I do the same too), I would recommend using an authorization code stream, since it does not open the marker in the browser. Read http://alexbilbie.com/2014/11/oauth-and-javascript/ . Instead, use a thin server proxy to add tokens to the request. However, I generally avoid using any server code on the server (for example, JSP in java or erb / haml in rails), since it connects the client too much with the server.

For each application, for example. admin cms, I will have to generate the AppID, which is passed to the auth server. No application secret required?

You will need the client ID for the implicit stream. If you use an authorization code stream (recommended), you will need both an identifier and a secret, but the secret will be stored in a thin proxy server on the server side, and not just on the client side (since it cannot be secret in this case)

Is it possible to use google login in this case (instead of username / password)? Does OpenID include a connection?

Yes. Google uses openid connect

How can I implement all this in NodeJS? I see https://github.com/jaredhanson/oauth2orize , but I do not see how to implement an implicit stream.

The good thing about openid connect is that (if you use another provider, such as google), you do not need to implement the provider yourself, and you only need to write the client code (and / or use client libraries). See http://openid.net/developers/libraries/ for different certified implementations. See https://www.npmjs.com/package/passport-openidconnect for nodejs.

+2
source

All Articles