Stormpath-express login does not work with basic username:password authentication

166 views Asked by At

I am trying to create a NodeJS API system for an electron-based desktop application. The app should allow basic login using username and password, after the user logs in, all subsequent API calls are authenticated via ids and secret keys. I am referencing this guide on using express-strompath description here. I am unable to perform username/password authentication like this.

curl -L -H "Content-Type: application/json" -X POST -d '{"password":"Som3Pa55Word", "username":"[email protected]"}' http://ec2-54-88-168-7.compute-1.amazonaws.com:8000/api/v1.0/login

Or via javascript

function Login() {
      ...
      var user = {
        username: '[email protected]',
        password: 'Som3Pa55Word ',
      }
      var req = {
        method: 'POST',
        url: apiBaseUrl + '/login',
        headers: {
          'Content-Type': 'application/json'
        },
        data: user
      }
      return $http(req).then(handleSuccess, handleError);
    }

However, when I user the API Key, I am able to log in.

curl -L -H "Content-Type: application/json" -X POST --user ABCDEFGHIJKLMNOPQRSTUVWXYZ:AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz -d '{}' http://ec2-54-88-168-7.compute-1.amazonaws.com:8000/api/v1.0/login

Or via javascript

      var url = apiBaseUrl + '/login';
      var sp_api_key_id = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
      var sp_api_key_secret ='AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz';

      get the Resource object w/ custom "get" method
      $resource(url, {}, {
        get: {
          method: 'GET',
          headers: {
            Authorization: 'Basic ' +
              $base64.encode(sp_api_key_id + ':' + sp_api_key_secret)
          }
        }
      }).get().then(function(result) {
        console.log("Loging Success")
      });

Obviously it's inconvenient to have users enter their API keys into a form for authentication. I was wondering why stormpath-express accepts API ID/Secret combinations but not username/password.

Here is the code for my nodejs server

router.post('/login', stormpath.loginRequired,  function (req, res, next) {
    /*
    * If we get here, the user is logged in.  Otherwise, they
    * were redirected to the login page
    */
    var respnse = {
      message: 'If you can see this page, you must be logged into your account!'
    }
    res.json(respnse);
    res.status(200);
  });

And Stormpath setup code

// Config
app.use(stormpath.init(app, {
  // TODO
  // apiKeyFile: './app/config/stormpath_apikey.properties',
  application: 'https://api.stormpath.com/v1/applications/ABCDEFGHIJKLMNOPQRSTUVWXYZ',
  secretKey: settings.stormpath_secret_key,
  web: {
    login: {
      enabled: false
    },
    register: {
      uri: '/user/register'
    },
    preLoginHandler: function (formData, req, res, next) {
      console.log('Got login request', formData);
      next();
    }
  },

  postLoginHandler: function (account, req, res, next) {
    console.log('User:', account.email, 'just logged in!');
    next();
  }
}));

2

There are 2 answers

1
robertjd On

I work at Stormpath. The API Key authentication feature, where accounts are issued API keys, is meant to be used for server-to-server clients, not web browser clients. As such, API Keys are meant to be used with HTTP Basic Authentication or to be exchanged for OAuth2 access tokens. Both of those strategies are described in this documentation:

http://docs.stormpath.com/nodejs/express/latest/authentication.html#http-basic-authentication

http://docs.stormpath.com/nodejs/express/latest/authentication.html#oauth2-client-credentials

Web browser clients are meant to use the /login endpoint, and they receive an Oauth2 access and refresh token in response (we store these in secure cookies). This is a special nuance of express-stormpath. You can do a proper OAuth2 password exchange by using the oauth/token endpoint, that is also described here:

http://docs.stormpath.com/nodejs/express/latest/authentication.html#oauth2-password-grant

I hope this answer helps!

0
Wakahiu Njenga On

For web-based clients based on angularJS, we can either used the /login endpoint, and allow the browser to manage the cookies it sends, use the /oauth/token endpoint to receive an access and refresh token. The oauth2 method is described in detail here and here. The oauth2 method allows one-time exchange of their API Keys for an Access Token. This Access Token is time limited and must be periodically refreshed.

function Login(user) {
      var apiBaseUrl = "https://api.stormpath.com/v1/applications/ABCDEFGHIJKLMNOPQRSTUVWXYZ";
      var sp_api_id = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
      var sp_api_secret = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
      var req = {
        method: 'POST',
        url: apiBaseUrl + '/oauth/token',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          Authorization: 'Basic ' + $base64.encode(sp_api_id + ':' + sp_api_secret)
        },
        data:  'grant_type=password&username=' + user.email + '&password=' + user.password
      }
      return $http(req).then(handleSuccess, handleError);
    }