I am currently working on an app with a React frontend and a Node/Express backend. There are certain functions of the app that I only want an admin user to be able to use, so I want to implement an admin login form that takes a username and password. This would be the only user that this app has.
How would I go about implementing this? I've looked at technologies like passport.js and express-basic-auth, but I'm wondering if there's a simpler way to implement this since there is only a single user. Any advice would be greatly appreciated!
If you wanna do it by yourself then whenever the user logs in the application, create an authtoken for the user and save it in the backend and send the authoken as the response for successful login. Further save the authtoken as a cookie on the frontend. Next will be while performing any action you need to send the authtoken to the server. If that authtoken is present on the server side you go on with the action or else send the response error saying that the authtoken is invalid of something like that. On loggin out of the application remember to expire the cookie and also remove the authtoken from the backend.
You can add this if you want where if the authoken provided is incorrect you can simple remove the authtoken from the backend and redirect the user to login page expiring the cookie from the frontend.
I have my frontend using React/Next.JS, and I'm wanting to implement Google OAuth for authentication to the users info in the backend.
On the backend, I'm using Express and Passport for routing and authentication respectively. I got all of this working with just the plain username and password, however I decided that I would rather have this with just using OAuth services.
So the current flow:
User on FRONTEND clicks "Login with Google", which redirects them to BACKEND/login/google, which then of course handles logging in with Google, which then once its done redirects to BACKEND/login/google/callback, which will then redirect you to the frontend.
Now here's the issue. On the callback route in my backend, calling Request.isAuthenticated() works just fine. However once the user has navigated back to the frontend, each subsequent request is not authenticated.
My thought here is that since the user is technically being logged in on the backend, the session is being tied to the backend.
What would be a proper way of handling this type of scenario?
I have this problem with Express(NodeJS)/Angular web app where I rely on Steam's login authentication. Essentially when the user clicks "Login" he's redirected to the Steam authentication(Steam's website), once logged in the user is redirected back to a specific route on my backend called /verify. Once the user hits /verify there are session variables containing necessary user data to access. Therefore I use JWT to generate a token with this data to send back to the client(Angular in this case).
The problem is sending this token back to the frontend(the client) to save in local storage.
Any help is highly appreciated! Currently, I pass the token via a query string with a redirect back to the frontend, but this doesn't seem like a good solution.
Maybe I should stick to server-side sessions and write HTTP routes to GET user data. The problem with this approach is once again the client is completely unaware when the user authenticates himself on the backend, since the only callback is triggered is on the backend.
EDIT:
Tried another approach, however once again unsure of it's the right way to go both code-wise and security-wise.
Redirect the user to the Steam authentication page.
Wait for the authentication callback on server side, in my case it hits the route '/verify'.
Once at /verify the session cookie is already set, therefore I redirect the user back to my Angular app to a specific route called '/login'.
On /login the user requests a token based on the session cookie on the server, the token in my case is a JSON Web Token(JWT).
Once the token is saved in local storage I simply redirect the user to any page in my Angular app.
If this is the wrong way to do it, please let me know!
I've been scratching my head for about 2 days on how to solve what seemed to be a simple task, but it's starting to drive me crazy.
I have an application where users will use SAML 2.0 to authenticate.
I have a react-application set up for the front-end, and was thinking I was gonna use JWT to secure the rest-api communication between front-end and backend.
When a user signs in, the flow is the following:
User accesses www.server.com/ and gets served the static HTML with react-application
User clicks 'Sign in' and accesses www.server.com/login
passport-saml redirects user to saml identity provider. User logs in.
User calls back to www.server.com/callback with a SamlResponse in the req.body which is decoded by passport-saml and put into req.user.
If the user doesn't already exist, I create the user in the database.
I create a JWT.
What should I do next? The problem is that the user is not in the react-application when calling back from the identity provider, so I've lost all state in the application, so whatever I reply with will get sent to the browser.
Is there any way I could force the browser to give me the SamlResponse which the identityprovider is calling back with? Then I could send it to the server as a http-request from the react-application.
After some thinking, I came up with the following solution which worked quite nicely for me.
SAML has something called RelayState which is a property that the Service Provider has to respond with. So now the process looks like this:
User accesses http://frontendserver.com and gets server the static page with the React application (not signed in.).
User clicks 'Login' and gets redirected to http://backendserver.com/login/?RelayState=http://frontendserver.com which authenticates via passport-saml and redirects user to SP. So I pass the origin of the request in RelayState.
User calls back to http://backendserver.com/callback with the SamlResponse, which includes the RelayState.
I create a token, and redirect the user to RelayState/#token.
I can then parse the url in the React application, and add the token as a header for any further requests.
This might've seemed like the obvious way to do it, but it took me quite a while to figure out that this would work.
I know this question is for Node backend, but I found an article of the implementation for a PHP/Apache webserver backend here and I think it can help someone trying to understand the flow of the process of how this type of thing works.
How does one handle authentication (local and Facebook, for example) using passport.js, through a RESTful API instead of through a web interface?
Specific concerns are handling the passing of data from callbacks to a RESTful response (JSON) vs using a typical res.send({ data: req.data }), setting up an initial /login endpoint which redirects to Facebook (/login cannot be accessed via AJAX, because it is not a JSON response - it is a redirect to Facebook with a callback).
I've found https://github.com/halrobertson/test-restify-passport-facebook, but I'm having trouble understanding it.
Furthermore, how does passport.js store the auth credentials? The server (or is it service?) is backed by MongoDB, and I'd expect credentials (login & salted hash of pw) to be stored there, but I don't know if passport.js has this type of capability.
There are many questions asked here, and it seems that even though the questions are asked in the context of Node and passport.js the real questions are more about workflow than how to do this with a particular technology.
Let's use #Keith example setup, modified a bit for added security:
Web server at https://example.com serves a single page Javascript client app
RESTful web service at https://example.com/api provides server support to rich client app
Server implemented in Node and passport.js.
Server has a database (any kind) with a "users" table.
Username/password and Facebook Connect are offered as authentication options
Rich client makes REST requests into https://example.com/api
There may be other clients (phone apps, for example) that use the web service at https://example.com/api but do not know about the web server at https://example.com.
Note that I'm using secure HTTP. This is in my opinion a must for any service that is available in the open, since sensitive information like passwords and authorization tokens are passing between client and server.
Username/password authentication
Let's look at how plain old authentication works first.
The user connects to https://example.com
The server serves a rich Javascript application which renders the initial page. Somehwere in the page there is a login form.
Many of the sections of this single page app haven't been populated with data due to the user not being logged in. All these sections have an event listener on a "login" event. All this is client side stuff, the server does not know of these events.
User enters his/her login and password and hits the submit button, which triggers a Javascript handler to record the username and password in client side variables. Then this handler triggers the "login" event. Again, this is all client side action, credentials were not sent to the server yet.
The listeners of the "login" event are invoked. Each of these now needs to send one or more requests to the RESTful API at https://example.com/api to obtain the user specific data to render on the page. Every single request they send to the web service will include the username and password, possibly in the form of HTTP Basic authentication, since the service being RESTful isn't allowed to maintain client state from one request to the next. Since the web service is on secure HTTP the password is safely encrypted during transit.
The web service at https://example.com/api receives a bunch of individual requests, each with authentication information. The username and password in each request is checked against the user database and if found correct the requested function executes and data is returned to the client in JSON format. If username and password do not match an error is sent to the client in the form of a 401 HTTP error code.
Instead of forcing clients to send username and password with every request you can have a "get_access_token" function in your RESTful service that takes the username and password and responds with a token, which is some sort of cryptographic hash that is unique and has some expiration date associated with it. These tokens are stored in the database with each user. Then the client sends the access token in subsequent requests. The access token will then be validated against the database instead of the username and password.
Non browser client applications like phone apps do the same as above, they ask user to enter his/her credentials, then send them (or an access token generated from them) with every request to the web service.
The important take away point from this example is that RESTful web services require authentication with every request.
An additional layer of security in this scenario would add client application authorization in addition to the user authentication. For example, if you have the web client, iOS and Android apps all using the web service you may want the server to know which of the three the client of a given request is, regardless of who the authenticated user is. This can enable your web service to restrict certain functions to specific clients. For this you could use API keys and secrets, see this answer for some ideas on that.
Facebook authentication
The workflow above does not work for Facebook connect because the login via Facebook has a third party, Facebook itself. The login procedure requires the user to be redirected to Facebook's website where credentials are entered outside of our control.
So let's see how things change:.
The user connects to https://example.com
The server serves a rich Javascript application which renders the initial page. Somehwere in the page there is a login form that includes a "Login with Facebook" button.
The user clicks the "Login with Facebook" button, which is just a link that redirects to (for example) https://example.com/auth/facebook.
The https://example.com/auth/facebook route is handled by passport.js (see the documentation)
All the user sees is that the page changes and now they are in a Facebook hosted page where they need to login and authorize our web application. This is completely outside of our control.
The user logs in to Facebook and gives permission to our application, so Facebook now redirects back to the callback URL that we configured in the passport.js setup, which following the example in the documentation is https://example.com/auth/facebook/callback
The passport.js handler for the https://example.com/auth/facebook/callback route will invoke the callback function that receives the Facebook access token and some user information from Facebook, including the user's email address.
With the email we can locate the user in our database and store the Facebook access token with it.
The last thing you do in the Facebook callback is to redirect back to the rich client application, but this time we need to pass the username and the access token to the client so that it can use them. This can be done in a number of ways. For example, Javascript variables can be added to the page through a server-side template engine, or else a cookie can be returned with this information. (thanks to #RyanKimber for pointing out the security issues with passing this data in the URL, as I initially suggested).
So now we start the single page app one more time, but the client has the username and the access token.
The client application can trigger the "login" event immediately and let the different parts of the application request the information that they need from the web service.
All the requests sent to https://example.com/api will include the Facebook access token for authentication, or the application's own access token generated from Facebook's token via a "get_access_token" function in the REST API.
The non-browser apps have it a bit more difficult here, because OAuth requires a web browser for logging in. To login from a phone or desktop app you will need to start a browser to do the redirect to Facebook, and even worse, you need a way for the browser to pass the Facebook access token back to the application via some mechanism.
I hope this answers most of the questions. Of course you can replace Facebook with Twitter, Google, or any other OAuth based authentication service.
I'd be interested to know if someone has a simpler way to deal with this.
I greatly appreciate #Miguel's explanation with the complete flow in each cases, but I'd like to add some on the Facebook Authentication part.
Facebook provides a Javascript SDK which you can use to get the access token on client-end directly, which is then passed to the server and used to further pull all the user information from Facebook. So you don't need any re-directs basically.
Moreover, you can use the same API end-point for mobile applications as well. Just use the Android / iOS SDK for Facebook, obtain the Facebook access_token on the client end and pass it to the server.
Regarding the stateless nature as explained, when get_access_token is used to generate a token and passed to the client, this token is also stored on the server. So it's as good as a session token and I believe this makes it stateful ?
Just my 2 cents..
Here is an awesome article I found that can help you authenticate with:
Facebook
Twitter
Google
Local Auth
Easy Node Authentication: Setup and Local