Basically,
I have SPA app with JWT authentication. Now my question is, there is a page that has follow button, so on the first load of page, I need to know if user is logged in or not, so I can disable/enable button.
Approach 1: Before page load send access token and if it is successful render like user is logged in, if it fails render like user is logged out
Approach 2: When user is logged in, keep that state in LocalStorage and just check local storage and render page from that
Is it correct to just keep state of logged in user in LocalStorage? I think that is where you should store ID token (if you use them) that only has user profile information?
Of course I will check access token on each request and from response I can change state in LocalStorage. Problem is that on initial load of page, should I check access token server-side before rendering?
If I keep state in LocalStorage than that user will be logged in on that device basically indefinitely, until he clicks "log out" or tokens fail?
Can anybody see potential problems with keeping state in LocalStorage?
It's OK to keep this information in the local storage. I mean, you can keep a variable there, that will just tell you "this user is logged in as userX". You can then safely utilize this information to display information on your page (e.g. Hi userX!). Even if someone manages to steal that information, it doesn't give them much information.
As you said, you will have to check the credentials on every request anyway (access token, session cookie, etc.), so it's not an issue to have this non-sensitive data in the local storage.
You can of course go with approach 1, but in my opinion, it's just adding unnecessary traffic.
If it bugs you that it will seem that the user is logged in for ever, then you can also persist some TTL in the local storage, and after that TTL treat the user as logged out.
Related
I am managing performing a login and the login state using Vuex. It is a standard procedure of:
User submits their login details on a form
The form dispatches a Vuex action to make an axios API call to a Node/Express endpoint /api/login with the credentials
The response from the API if successful will send back the user's data which is stored in the state.user object through a setUser mutation. A flag of state.user.isLoggedIn is also set to true.
A JWT access token is sent to the user's browser and stored in a secure cookie to use over and over again until it expires. If it expires, a refresh token is used to generate a new JWT access token.
The site's header displays the user's login information .e.g name
The above all works as expected. However if the user refreshes their browser, then Vuex state gets emptied and the site header no longer shows the user information. To overcome this I stored state.user into localStorage in the browser as persisted data and repopulate the Vuex store using the data in localStorage on page refresh. If the user logs out, the localStorage is cleared.
There are many routes that require checking if the user is logged in. I cannot rely on localStorage because it can be manipulated by the user. If the user deletes their cookies which contains a JWT, then localStorage is not being emptied and the site header still displays their log-in information. Therefore I need to do an API call on almost every page to check if the user is logged in and if not then to delete the localStorage as well.
My question is:
Where do I perform a log-in check every time a page/view is accessed? Is it whenever the Vue app is mounted or within vue-router using the beforeEach navigation guard?
If I use beforeEach in vue-router, is it going to crash the site by making an API call to /api/login every time a user changes route? Is it normal practice to do this on every route?
Are there any other alternative patterns to keeping track of if the user is logged in or not?
Application decisions like this tend to be subjective because every application is different, with different requirements and different architectures. It sounds like this is a single page application, so I'll go from there.
First, the fact that your JWT is set up and working is great - that can be a lot of hard work, so be proud that you made it that far.
If your application has certain pages that are accessible without first being logged in (like a login page, or an access denied page, etc.), then you have to consider that in the design as well. In this case, a beforeEach route guard is the perfect solution to keep a route from loading or to catch those not-logged-in users before they attempt to request content that will likely just give them an error.
You probably shouldn't have to make an API call to the server each time the user navigates to a new page. That would probably be a little slow. Because your application uses JWT, complete with refresh tokens, you should be able to rely on them, so that if a user is logged in, they will continue to be logged in until they close their browser and walk away.
This is why you should not use localStorage. When a tab closes or even after a reboot, the user will still appear to be logged in. Instead of using localStorage, use sessionStorage - Helpful MDN link.
Now, the login event to retrieve the user object should only happen once per browser tab, but stay active during the visit.
I wonder why you don't just request a new user object from the server when the browser is refreshed. It's not strange to force a re-check to the server for a full page load. Doing that would mean you wouldn't have to use anything outside of Vuex to store the user's state
Next, is there a way to check the validity of their JWT during the navigation event? Depending on the way you handle the JWT, you may have access to it, and can possibly decode it (like through the oidc-client-js library), and that way determine for yourself if the token is expired. However, if the token is expired, your token refresh system may just refresh it and not tell you about it.
You can also watch your HTTP requests and look out for 401 or 403 responses (however your back-end handles logged-out users), and direct the user back to the login screen if you see one of those. You can use Axios' global interceptors to catch them, or do it yourself if you centralized the location from where Axios is called.
Overall, you're on your way, and clearly have a good grasp on this. Great progress so far, having done probably 90% of the heavy lifting already.
I’m building a react native app that will interact with APIs that I also write/manage. I have found Auth0 documentation for implementing this flow, but I’m not sure on where/when to save the tokens. I want to be sure I nail this step, because I feel like it has the potential to reduce the security of the flow by a great deal if I don’t do it correctly.
Here is the flow as I understand it (no error handling, only happy-path for sake of brevity):
A user enters the app for the first time, or is not already logged in
They log in using the Auth0 web-login-thingy
I receive a token
I can use the token to authenticate with my API
Questions:
Do I store that token? I don’t want my users to have to log in every time they use the app. If I do store the token, where do I store it?
If I’m not storing it, what do I do? Do I ping an authentication/authorization endpoint with Auth0 every time they open the app and get a new token?
Say I am storing the tokens, if I'm using the ID token for user data, should I be hitting the API again regularly to keep it up to date? Only when the user opens the app again? Not until they trigger a change in the app?
Instead of using the ID token for user data, should I just use that to get the user's ID and ping my database for user data?
I have the basics of this flow, and I'm able to sandbox it, but I want to start applying production-ready app logic to this flow and that's where I'm stuck. I’m a little lost here, so any help is good help.
Thanks!!
Here's a brief answer to your questions when using Auth0:
Yes! you store it, the most secure way to store the token is in your device's local storage, that way it is not kept either in application's state or in a global variable.
2&3. See above, but to add more information, you can configure your tokens to have an expiry length. in theory you would convert this 'expiry time from inception' to a date object, and can do one of two things; you can request a new token using the Refresh Token (that comes with the original) once the expiry has been reached, or force the user to re-log in and re issue a new token at this time (i prefer the latter, prevents people from just renewing their tokens forever as long as they remain logged in)
Use the auth token to request user information after login, this can be stored in app state/global variables/wherever. You then want to use the auth token in the Authorization Header for each API call, along with whatever data you are sending. this ensures that even once someone is INSIDE the application, they need to have a valid token to actually do anything involving data (imagine someone back-dooring into your app and skipping the authorization, or using something like postman to just hammer your API with garbage). it would work something like this: GET userData { Header: auth token } -> GET userProfile (by sending your user ID returned from GET userData) PLUS {Header: auth token }
I can give more in depth examples if you wish, and i apologize if i misunderstood any of the question and gave redundant/incorrect answers
Edit: Resources about using secure storage for keys
Document for when to use in-memory storage Vs persistent storage. The TL;DR is use in-memory if the key is expected to expire before a standard session duration, and persistent for storing a key between sessions
https://hackernoon.com/mobile-api-security-techniques-682a5da4fe10
link to Keychain Services doc
https://developer.apple.com/documentation/security/keychain_services#//apple_ref/doc/uid/TP30000897-CH203-TP1
link to SharedPreferences doc
https://developer.android.com/reference/android/content/SharedPreferences.html
AsyncStorage is a simple, unencrypted, asynchronous, persistent,
key-value storage system that is global to the app. [1]
You could store it in your AsyncStorage, but thats not necessarily a secure location itself (e.g. not encrypted, accessible on rooted devices...). Typically clients will issue access tokens that last anywhere from several hours to a couple days and these will provide their owner access to your API-resources. If there is sensitive data behind your login screen, you're probably better off simply re-doing the auth-flow and invalidate older access tokens on login.
I need to log in a user into Dropbox using Core API. Then remember his/her access token and allow logging in with another credentials (looks like a second Dropbox user). But when I make request to https://www.dropbox.com/1/oauth2/authorize it automatically ends up with redirect page with first user's access token giving no chance to enter another credentials. I know I can revoke first access token but then I will not be able to silently come back to first user.
Does anyone know is the possible to implement?
You can set the force_reapprove parameter for the /authorize page to true to prevent the automatic redirect:
https://www.dropbox.com/developers/core/docs#oa2-authorize
Note that the /authorize page is hosted on www.dropbox.com though, so the user will get their www.dropbox.com session, even if force_reapprove=true is set. With that parameter set though, the user has the opportunity to switch accounts, using the dropdown in the upper right of the page, before authorizing the app.
If that's not sufficient for whatever reason, you can try to end the user's www.dropbox.com. The simplest way is to direct them to www.dropbox.com/logout first. Be sure to make it clear to the user what is happening though.
Or, if you control the entire browser, e.g., if it's an embedded web view in your app, you can clear the browser's cookies, which will clear the session, forcing users to log in again.
I am making an app where I need to have the user log in into their spotify account.
I would like to know how can I know if the user is already logged in or not into Spotify?
What I am trying to do in my application is ask to log in only if I have never logged in before and take the user through the authentication process.
If I have logged in before I want to skip the part where I ask the user to log in. This would have to work also if the user has logged in, left the app for some time and came back to it, I don't want to have to require a re-login by the user. How can I get that status from Spotify ?
I appreciate any guidance with this, thank you.
Since it's very likely that the access token has expired by the time you want to use it again, you would need to use the Authorization Code flow, storing the access token and refresh token of the user.
You can try making a request to an endpoint like Get Current User's Profile passing your current access token.
Should it fails, try refreshing it. If you get an access token back, then you know the user is logged in and you have a valid token you can use. Otherwise, consider the user is not logged in.
Where to store the refresh_token and access_token is up to you. You could do it in localStorage, or even better, in a database.
Well, you type username and password in form, hit "OK" button. Then data going to server side and check users database if that user is existed. Then it return user id. And what next?
That data is saved in cookies?
Does it mean, that with every clicked link, site login you to website again?
I mean,
you click some link on site
browser redirect you to that page
site checks your cookies
site grab username and password from cookies
site checks is that data is valid (via connecting to database)
show page to you
Is that correct?
User enters credential.
System validates credential.
Upon successful authentication, server saves user object into session.
System grabs user info from session.
System displays webpage.
Tadaa!! :)
UPDATE
To add a little more...
User visits the secured webpage.
System checks if session contains a user object.
If user object exists in session, allow user through to visit the page.
If user object doesn't exists, redirect user to login page.
You don't need to store user password in the session. In fact, it is highly discouraged. Checking to make sure the user object exists in the session is sufficient.
When the user clicks the logout page, then proceed to invalidate the session... that's it. :)
Almost correct. You rarely go to the database with every request. You usually set a cookie with a expiry date and save the user session and info in memory. So every time a request is made, if the user is not authenticated, you authenticate him, generate and send him a cookie with, say, 5h expiry. So, in the next 5 hours, whenever a request comes in with that cookie, you trust that the user is an authenticated, valid user and you don't have to check the database.
It's not how every site does it nor it is the only way to manage session and cookies but I think it is the most widely used.
You should probably use sessions, but that's pretty much the gist of it. That way the data doesn't accidentally persist.
I mean, for my simple site at home, that's how I do it. But it's still locally hosted, so the security is guaranteed to be crap.
Oh, and no need to check with the database whenever you click on another link -- too much time wasted.
Typically, an application takes advantage of the session that is established between the browser and the web server, and makes a note that that session is "authenticated". "session" is a built in feature of HTTP. If the browser is closed, or after a certain period of time passes, the session is automatically closed. If the user does an explicit logout, the application marks the session as not-authenticated.