I'm struggling with implementing a proper front-end auth solution for my de-coupled setup. It consists of the following:
Server-side Ruby API (using Warden for email/password auth)
Client-side Backbone.js app
I think I'm stuck at how to properly pass tokens from the server to the client.
This passage from staticapps.org explains the type of flow I'm looking to achieve:
The client directs the user to a server-side authentication process. This may be a JavaScript pop-up window or a browser redirect triggered by setting window.location.
The server authenticates the identity of the user via password, social sign-in, or other means.
The server creates a randomly generated token and associates it with the now authenticated user.
The server transmits the token back to the client.
The client includes the provided token on subsequent requests to the server as a proof of identity, granting the user access to protected resources.
Any ideas how to achieve this with Warden on the server?
Note
I should mention that I'm leveraging Rack::Session::Cookie which I assume will be the unique token that is passed back and forth?
Related
I am building a web application with a basic client-server architecure. The frontend runs with react (nextjs) and the backend is on rails. However, the questions will be more about the flow of the authentication/authorization + session handling on the frontend.
I am using an Oauth provider to handle the authentication but don't need any authorization from their part as I don't need the resources of the oauth provider (ex. drive, calendar etc.)
For the authorization, as I want to access resources of my API, it's the API itself that handles authorization on any request made by the client (frontend) to the rails API.
Right now for the initial authentication this is the flow I'm using, Taken from https://blog.prototypr.io/how-to-build-google-login-into-a-react-app-and-node-express-api-821d049ee670 :
Implementation details important for the following questions :
I am using JWTs as access token (those generated by my API) and I simply sign them using a secret key that's only available on my API so the access token is unreadable from the front end point of view.
On the frontend, it is a react app and I used the following package to handle the OAuth flow google-react-login
Information received, what to use from Google (OAuth provider)
1- I receive(amongst other things) an IdToken and an access token from Google. Also I'm apparently supposed to receive a refresh token (which I didn't see). For my use case, all I need is the idToken from Google is that right?
Revoking of a refresh token (logout), flow for a re-login?
2- From my understanding access tokens need to be short lived for security reasons. So I need to return a refresh token to my client app to be able to generate new access tokens frequently. However, once a refresh token hits its expriy time, do I need to log out the user and prompt him to re-login through Google and basically redo steps 1 through 5 (Please refer to Figure 1)?
How to maintain the session through the access token
3- From the frontend perspective, can I assume that simply having a refresh token means the user is logged in? Once the server revoke the access token and the refresh token that means the user is logged out and I need to ouput a view of the web application for an unauthenticated user? That means after every page reload I need to check for the presence of an access and refresh token?
Thank you
I think you could improve your security and lower complexity by one thing - replace issuing of your own JWT tokes by a custom OAuth2 server. This OAuth2 server could use Google as an authentication provider. This way, your would not know about Google and it would just use your own OAuth2 server.
Then you can decide how to use it - whether the frontend will be the OAuth2 client or the backend.
If you choose the frontend, you will use the auth code flow with PKCE (as a public client). The fronend will use an access_token to authorize its requests to the backend. This way, the frontend will handle a session using hidden iframes. See the OpenID Connect Session Management RFC.
If you choose the backend, you will use the auth code flow (with a client secret). This way, your backend can maintain the session using a cookie (with secure, HTTP-only, SameSite options).
You can read the OAuth 2.0 for Browser-Based Apps RFC for the current best practices.
I'm working on a project based on Phalcon which consists in two different stand-alone subprojects: a php + angular frontend and a php REST API.
I protected the API with OAuth2, using PhpLeague OAuth2 Server. The API server is the OAuth2's authorization server AND resource server.
This is the actual flow:
The user can browse the public endpoints of the frontend, and when hits a private page, gets redirected to the login page;
The login page has username and password, POSTs them to the frontend server;
The frontend server calls a public method on the API server, which is expecting a Password Credential Grant: it validates the credentials and sends back an access token and a refresh token;
The frontend server caches both the access and refresh token in session and uses it for some API calls: the first of those is the '/users/me', which gets info about the current user and its ACL on the frontend sections;
The frontend server sends the page to the browser, which loads its javascript files.
Now, OAuth2 states that access tokens should be short-lived and refresh-token should be long-lived: in the frontend server logic, the API calls which receives a 401 (caused by the expired access token) are retried by sending first the refresh token to obtain a new access token via a Refresh Token Grant. If this second call is rejected, I assume the user is no more logged in (refresh token expired / revoked).
The pages are using Angular to perform data and ux/ui management. My question is:
should the Angular code call directly the API server?
Actually the first thing my javascript code does is to get a config object from the frontend server, which contains the access token too, and uses it to make the calls to the API server. The problem with this is that i should rewrite again the "refresh token logic" in javascript (after it expires, i get 401s), and by what I have read on the subject i understood that it is better to not make the refresh token visible to the client (as it can generate new access tokens).
So i was thinking about a "two step approach", where every javascript API call goes to an endpoint on the frontend server which relays it to the API server, but this is obviously slower (JS -> FRONTEND -> API and API -> FRONTEND -> JS).
What is the correct approach? It's not very clear to me if the frontend should be considered as two clients (php + js) which should work separately or not, as I imagine that an hypothetical iOS app would be making calls 100% against the API server.
I have used the same approach in my own projects. The problem that we have is that the client is not secure. In order to generate / refresh a token, you need to pass secure information to the authorization server.
I have done the same as you basically, let the back-end handle the tokens and their temporary storage. You cannot and should not trust the client with important information which lets you generate tokens. In terms of delays, I wouldn't worry about it too much since you're not going to be doing that much extra work, you won't even notice the delays. I have a system like this built and used by hundreds of thousands of users with absolutely no issues.
Now, you have said a few things in here which make me wonder what you are doing.
OAuth2 is not a user authentication system, it's an application authentication system. You don't pass a user and their password and generate a token for them, you pass a ClientID and ClientSecret and they generate a token for you. Then you have an endpoint which gives you the user details for this user, you pass your userid or username and get the details of that user.
A token expired does not mean your user is logged out. Those are two completely different things. How are you going to expire a token for example, when your user wants to log out? You can't, your token will still be valid until it expires after the set amount of time has passed.
A token can be used for let's say half an hour, but your user may use the website for 1 hour. So before you hit any API endpoint, you could check ... has this token expired yet? if yes then you can go and refresh it and keep working without having to bother your user with a new login screen.
The whole point of an OAuth2 system is to make sure that only authorised clients can access it. A client is not a user, it's an application. You can have a website for example and you only want users of that website to access your API.
You can have endpoints like ValidateUser for example, where you take a username and a password and return a yes or no and then you log your user in based on that.
Irrespective of language/framework, second approach is secure and better than first one because to get access token by providing refresh token to Authorization server, it still requires Client ID and Secret which should never be passed to Browser for security reasons.
In first approach, to make a direct call it will not work if your Authz Server is hosted on different domain than your frontend server because of Same Origin policy of browsers. Even if they are on same domain, still you are exposing Client ID and Secret which will compromise your frontend server
I m working on an application that needs SAML to manage authentication with an OpenAM server.
Actually, I use Satellizer with OAuth2 implicit grant flow and I have the following :
Open angularjs app in browser
Click on the third party login button
A new window hover the existing one (with ng app) is open asking me my credentials
I fill them, and validate
The pages made its stuff (generating token)
The angularjs application gets the token through the windows (how it is possible ?)
I can use my application with the OAuth2 bearer / jwt token.
I need to have something that works the same using SAML. The fact is that I m completely lost and it seems that I should log onto the SAML server using my backend...
I don't really like this situation and I need to know if there's something better to do using client side application.
What is the "usual" authentication flow with client side app with SAML ?
Thanks for your help
SAML2 was designed at a time when the concept of client side apps with JavaScript was not yet invented.
A common method is to use an intermediate OpenID Connect/SAML2 proxy/bridge (e.g. IdentityServer3 + Kentor.AuthServices.Owin) to authenticate users:
User starts log in sequence in JS app.
User is redirected (part of OpenID Connect flow) to IdentityServer3.
User is redirected (part of SAML2P) to SAML2 Idp.
User authenticates at SAML2 Idp.
User is redirected back to IdentityServer3 (part of SAML2P).
User is redirected back to JS app (part of OpenID Connect flow).
This works excellent to get the user authenticated with an external Idp. If you have resources, such as backend services, those calls are usually authorized through an OAuth2 bearer token issued at step 6.
If your backend API is expecting a SAML assertion instead of a bearer token you will have to look at our ways though.
I own a Play Framework application acting acting as a backend server providing a set of REST APIs.
At client side, I own an AngularJS application that calls APIs from backend-server through AJAX.
Currently, I make use of a solution based on Session-token mechanism.
Meaning that each time a user logs in successfully, a cookie is retrieved at client side containing an authentication token.
At each request then, the cookie value (the auth token) providing by the client request is extracted on the server and if valid, the request is made.
Now I want to use OAuth 2.0. Reasons are? :
It's a great standard way to secure API, avoiding the use of a datastore (Memcached) to keep auth tokens at server side, as I'm currently providing.
I want to provide a better secure than a sole cookie, by providing some client_secret and nonces to avoid some replay attacks etc...
I want to restrict the amount of clients capable to call even public REST API I provide, meaning API that allows anonymous call, like listing a list of items for instance.
The point is that I don't involve a third party, since all protected resources are on my own.
I came across this article explaining how to secure internal REST API with OAuth 2.0 implementing a 2-legged instead of a 3-legged as usual.
However, I can't figure out how the Client Credentials flow could authenticate a specific user, when calling for a REST API that needs to have a user authenticated.
Indeed, Client Credentials flow seems to be based on a global client_id, client_secret keys (global to the app, so in my case to my Javascript app), and therefore not enough specific to target a specific user and controller its specific rights.
Any help would be great.
Seems like you should use "Resource Owner Password Credentials Grant" (https://www.rfc-editor.org/rfc/rfc6749#section-4.3). It is dead simple - put client ID/secret in Authorization header and put user name/password in query variables. Here is an example from the RFC:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
Server side you can check for both validity of the client (your javascript app) as well as the user. Just remember that it is impossible to protect the client credentials as it will be embedded in your (downloadable) JavaScript code. The user name/password is entered directly by the end user.
I've started using backbone.js with ASP.NET MVC 3 lately.
My server exposes a RESTfull API that my website works against.
Meaning - the authentication works with a dedicated "authenticate service".
authentication token for the user stored in client cookie.
No forms authentication, Server is stateless, no session.
How do I implement a client only "Forms authentication" alike mechanism
(With 'return url' and all) ?
Is there any javascript framework for that ? or should I implement all the routing, cookie testing and validations manually ?
I implemented something similar at one point, though with a java backend. The solution consisted of:
Server checks that there is an authenticated session for all calls, returns 401 Unauthorized if there is no valid session with logged in user
I added a global jQuery.ajaxError handler, that checks the http code of the error, if it's 401 I used backbone routing to show the login screen
Login screen implemented with backbone view, on submit I send a ajax request to server, server checks credentials and creates session
The advantage of this approach is that I could use normal session / cookie handling on the server like in any app and only have authentication code in one place on the client.