So I'm unsure of the practicalities of authentication on a SPA, as I try to get used to my new stack of choice.
I will be serving a Node/Express app, with all API routes on /api, and the frontend served on the root / (all routes will serve index.html, then the client-side routing will take care of the rest. So I have the backend authentication set up with the Passport library, which works well. But how does one keep the server and client sessions in sync? As well as taking care of security.
If I make a POST request to /api/login with credentials, what do I return in the response to the client? And where is the session set?
My frontend is Vue, so I assumed I would just pass the user data (if credentials are correct) to the instance and have a user object. But I'm guessing I need to store a token of some sort? (jwt?)
If someone could clear up how this client-server architecture works, that would be great.
Cheers.
Whenever user logs in with credentials you can send a JWT Auth Token and then store the token as Cookie/Local Storage.
Then send the token as Authentication Token in each request as Request Header/Data to validate the user.
Link: Here is a tutorial with NodeJS
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.
There is Spring MVC application - the server produces HTML, the client is not SPA (i.e. this is not about API in any form).
During authentication JWT token is generated and returned to the client. During authorization the server verifies JWT token.
How to store JWT token on client side and pass it via all further requests to the server? Remember this is Spring MVC application and not SPA.
I tried to google for any examples but the only findings relate to REST authentication, that doesn't relate to this case at all.
In worst case we can perform authentication from JavaScript and store JWT token in cache/cookie. But maybe Spring MVC supports this out of the box and we need just to set some checkbox in configuration :-)
For non-SPAs, the usual approach is to store the authentication token in the server session. When the client makes a request, the appropriate session is retrieved via the JSESSIONID cookie (or the JSESSIONID is added to the URL if cookies are disabled).
I'm not sure why you can't use the approach above, but if you want to store the JWT on the client, a common approach is:
store the token in the browser's local or session storage when it's generated, e.g. window.sessionStorage.authToken = 'token_value';
add the token to each subsequent request by setting the Authorization HTTP header to the value of the token
when the user logs out, delete the token from browser storage
I can use "Set-Cookie" header with JWT token from server side. The client will interpret this header as setting a cookie automatically. In this case passing the token to every requests will be done without additional steps from client side.
Some details are described here https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage
I will use this as an accepted answer until a better option provided.
I'm working with auth in Nextjs, I'm wondering what is the best strategy to handle authentication in NextJS ?
Here my services structure :
If I understand well I have to handle the server side rendering in NextJS, so I understand I have to put cookies from my external server to my NextJS client, then handle the server side rendering checkings. To do that I assume I have to create connection between the NextJS server and the other services. Before dive more deeper in the subject I would discuss with you about the possibilities available to me. It seems the NextJS auth is a subject in plain development.
Any hint would be great,
Thanks
I've recently added an example with cookie auth which explains what you are trying to do on the frontend.
For the backend, optimally you'll have your API in an external server, apart from the server you use for rendering your Next.js app. This API will handle the database and the token creation business. Then the basics of the authentication are like this:
The client POST a request with username and password to the server.
The server gets the request and generate a token based on the data received.
If everything went okay validating the data, the server responds with the token, e.g., { token: "secrettoken" }.
The client receives the token and saves it in a cookie. Optionally you redirect the user to the /dashboard or /profile if everything is okay.
The client, on restricted pages, will check if the cookie exists and optionally validate that against the server, you do this last part in getInitialProps. If the cookie validation fails you redirect the user away.
I've created a small library to abstract this logic.
So in the end, your Next.js app shouldn't know what's happening in the server, it only should receive the token, save it, validate it, and redirect the user if something is wrong.
How you want to handle the token creation, on the external server, is up to you.
Check out this thread. There are several examples of how to do Authentication with JWT, OAuth etc throughout the thread. You'll see that the examples are utilizing getInitialProps and there are several examples utilizing cookies throughout to extract the Authentication tokens.
You'll have to write a custom server.js file using express.js to serve the tokens through your route requests. I'm assuming by "external server" you mean some third party Authenticator using OAuth or OpenId protocols to retrieve tokens. If so, you're right to say that you'll need to request the tokens (or Authentication mechanism) from those external services and then decide how you're going to utilize them in your own client. You'll probably be using getInitialProps to do what you need to do with your Authentication tokens in the client once you are rendering to the browser.
More examples of Authentication here -- one for firebase and another for Apollo.
Just to add to the answers if you want to use Auth0 specifically. In the interview on http://www.fullstackradio.com/112 around the 1:06 min mark Guillermo Rauch mentioned that if he were to implement authentication all over again he would use Auth0, so I created a minimal repo using Auth0 and Nextjs with Serverless functions.
Like #jolvera suggested there is an API in an external server, apart from the server used for rendering the Next.js app. This API is located in ./auth/auth.js. It handles the token creation business, and could be extended to handle the database.
The HOC component in ./utils/withAuth.js calls the auth.js lambda for the user information, and is only able to retrieve it if the client side is authorized. Otherwise the user information is undefined. Additionally there is an event listener similar to the one in with-cookie-auth which syncs logouts across tabs.
Also one other note, don't get confused with the Nextjs example on Auth0's blog. That example is extending the Nextjs server, and isn't the solution you want if you are deploying Next to serverless. It doesn't have the separation of concerns with page routing and authentication.
I'll put them in context first.
I am developing a Rest API using laravel and as an oauth2 authorization method using Laravel Passport as an implementation.
On the other hand I am developing a Javascript client (Single Page Application or SPA) that will consume the API Rest.
The situation is as follows:
Some API Rest endpoints must always be accessible by the client (a valid client since the API is not public) and other endpoints must only be accessible by the client when a user is logged in.
In a first approach what has been proposed is that when the SPA is initially opened in the browser, you get a Client Credential Grant Token so that it is a valid client and can make requests to the "Basic" endpoints of the API. Later, when a user logs in, a Personal Access Token will be generated which will allow the client to make requests to all endpoints of the API Rest.
I'm a little confused as to how to put this into practice.
I hope, please, you can help me.
I have a React app with backend API written in Express (all /api calls are proxied there).
Upon successful user authentication, I will be generating a session ID and storing it somewhere on the client side so that I can later authorise requests to the API.
What is the best practice of implementing this architecture on the Express side? Shall I just send the session ID along with the body of each API request and then precede all backend calls with an authorisation mechanism? Or is there some better/easier way of doing this?
My intuition would be to take two steps.
On the client, set up your HTTP client to pass the sessionID as a header. You can set custom headers using an HTTP client like axios or, in ES6, fetch, and apply those headers to every request send to your Express API.
Set up a middleware function on your app that will run on every request received by the server. Express has an easy way to do this using app.all("*", yourAuthFunction). You can also take a look at app.use for applying a middleware to more specific routes. This will ensure that your sessionID gets verified on the server before any data is sent in response to the client. Of course, you'll have to write the auth function to work how you'd like.
Good luck!
When the user successfully authenticated (it should auth' anytime the page loads), a response should be sent to it (contains the session token).
Every other request should be authenticated with the session token that received on the authentication response.
You can store this token value into hidden input <input name="session" type="hidden" />