Now this wasn't simple for me to figure out initially! Partly because, in my mind, the confusing docs surrounding Google oAuth2 where they state:
When a user grants access to your app for a particular scope, the user is looking at the user consent screen, which includes project-level product branding that you set up in the Google Developers Console. (For information about setting up the consent screen, see Setting up OAuth 2.0 in the Developers Console help.) Therefore, Google considers that when a user has granted access to a particular scope to any client ID in a project, the grant indicates the user's trust in the whole application for that scope.Now, I read that as: when you collect an authentication code from one medium within your applications "product" suite, provided other parts of that suite use a client ID that share the same "project" at Google's end - then you can use that client and authentication code to gain an access token - and thus validate the user. Apparently not so! I spent ages going round in hoops over this and settled on a simple setup which means I can authenticate the user on both the client (Ember) and server (Sails).
To make things clear - the idea of all this is to provide a sensible UX for a browser application to authenticate using 3rd party auth services. This includes having the auth flow inside the application and as we are an SPA we don't want to have any nasty page refreshes or redirects (in the main browser). I am pulling in a few other libraries to achieve this and have had to modify the Waterlock library slightly to enable this to work. I'll be cleaning that up and pushing back to Waterlock soon but for now I have included the deps as submodules inside our repo.
The desired flow is:
- User clicks "authenticate with Google" button
- Popup appears with Google's auth flow
- User provides access to our app
- Popup closes (main app never refreshes or redirects)
- Our app receives the authorization code from Google
- Sends that code to our API
- Our Api then validates that code by exchanging it for an access token
- If the code is valid we find or create a user and set up the JWT for the client app
- Our client app receives the JWT and uses that for future requests to the server
ember server --proxy http://localhost:1337Simple!
In terms of changes - I have included a modified version of waterlock-google-auth in the API - this has a simple setup in /config/waterlock.js - you can see the required bits in my repo and by reading the readme on the main repo. The changes I had to implement were to ommit the requirement of the client to provide a CSRF - I may add a step where the client can retreieve one before starting the auth flow - I may omit it by using a separate endpoint for SPA auth - not sure of the implications yet. That's all for the server!
The client has a few new pieces:
- I've included the ember-cli-simple-auth-torii package - this handles auth flows requiring a popup
- I've also included the ember-cli-simple-auth-oauth2 package
- And finally the torii package.