sahat / satellizer

Token-based AngularJS Authentication
https://satellizer-sahat.rhcloud.com
MIT License
7.85k stars 1.13k forks source link

Configuration of oauth to work with cross-domain Rails API #253

Closed simonasdev closed 9 years ago

simonasdev commented 9 years ago

Hello, I have tried to implement oauth flow with satellizer and rails-api, which I host on a different domain than my angular app, with facebook oauth provider. Problem is, I can't figure out which options for the $authProvider.facebook do what, specifically url and redirectUri. If I host my API at http://localhost:8081, facebook oauth endpoint is at /auth/facebook, which is handled by omniauth-facebook gem, and callback is at /auth/facebook/callback, how should I setup my $authProvider? Am I thinking and trying to implement it in the correct oauth flow way (the implicit grant, as I understand)?

Several things I have tried were setting redirectUri: 'http://localhost:8081/auth/facebook', which worked and I got the data with email and name from facebook successfully, but didn't understand how would I send the jwt token back to the client from popup window. I have analyzed https://github.com/sahat/satellizer/wiki/Login-with-OAuth-2.0, but now to me appears that I can't be at step 9, since popup window has not been closed yet, so there must be a flaw in my flow. So another question would be could you elaborate what is happening, both in client and server side, at each oauth step, what options from configuration are used, what params should be sent and received. I understand that is more of a server side issue since I don't know what I'm doing and everything from my satellizer app seems to work, but I believe this is more of configuration problem or the way I understand this oauth flow, that satellizer uses. I could contribute to the server side examples with ruby on rails, if I got everything to work.

sahat commented 9 years ago

That's a lot of questions in one issue. Satellizer was designed, by default, to work with explicit grant flow. That means you still need a server. However, your redirectUri should point to the same URL as your Angular app and not /auth/facebook/callback. Which is why all default redirectURIs are set to window.location.origin. Satellizer will grab the ?code= value and close the popup automatically. Once it has code it will send it to your server at $authProvider.facebook.url which defaults to /auth/facebook. From there on I don't know what Omniauth expects as I usually just implement it myself if you look at other server examples.

Sending JWT is handled by the server. You have to implement that function yourself using one of the JWT libraries for Ruby. Once your server gets the code, you exchange it for access token, fetch profile info, save it to database and then create a new JWT token using your custom function and send it back to the client as JSON: { token: "my json web token" }.

Note: The key token must match $authProvider.tokenName which defaults to token, but you can call it access_token or whatever you want just as long as Rails backend and Satellizer agree on the same naming.

If you have any more specific questions about my explanation please feel free to ask. Look at Python or Node.js examples to see how it is implemented. For Satellizer + CORS in action check out this repo: https://github.com/sahat/instagram-hackhands

simonasdev commented 9 years ago

It appears that I was able to get it work. Issue was that flow that satellizer uses is quite similar to both implicit and explicit (Authorization) flows, but not quite exactly. So I did need to roll my own server side oauth flow, since omniauth gems for rails handle only exact Authorization flow (as far as I know) with requests and redirects, so trying to access routes while having omniauth rack middlewares in the stack always broke something. I implemented it by manually making requests to facebook and google api endpoints as in examples for python, but it looks ugly so far. I'll let you know when I'll be ready to share my examples.

sahat commented 9 years ago

Using the manual approach was, and still is, the best choice for Satellizer if the goal is to cover a wide range of languages and frameworks. I was even planning to add Rust to the list of examples but at the time there was not even a JWT library for Rust, let alone something as powerful as Omniauth.

I am going to close this issue. If you would like to contribute a Rails example that would be great.

However, one problem I had with Rails when I was evaluating it - there seemed to be no way to change the public directory path. I would like to point the public directory to ../client/ in order to avoid duplicating Angular.js client-side app multiple times for each server-side example.

tagazok commented 9 years ago

Any chance to see an example with rails in the repo? (the ruby looks really empty ^^')

simonasdev commented 9 years ago

Coming soon!