How to plug logic into session invalidation due to cookie expiration - ember.js

In my app, I want to send some request to the api on session invalidation.
I want to be able to differentiate when a user logs out (clicks on the button), and when he is automatically logged out (eg, after inactivity period, cookie expiration...)
I think I've managed most of the use cases, the only remaining one is to be able to 'plug' some logic when the cookie expires, but before the session is cleaned-up.

Related

Display content based on sign in state via OAuth

I have my api behind a third party OAuth (ex. google, twitter, etc). When a user hits /api/login, they are redirected into the OAuth flow and then sent back to my callback /api/login/callback. I store their login info and then send back a same-site http only session cookie to validate their user id. On subsequent requests, I retrieve that session cookie to get their user info and then perform requests using the OAuth token stored earlier.
Now, I want to create a frontend to go with my backend REST api. When a user goes to my / route they get a generic about page along with a sign in button. The sign in button redirects to my /api/login route and eventually back to my /api/login/callback. Now, the callback will redirect again to the / route. Subsequent requests made will have the session cookie attached and will go through.
My problem arises in that I don't know how to communicate to my frontend that my user is logged in. Because my session cookie is http only I can't access the cookie on page load to render a different UI for logged in users.
Some ideas I've had:
Hit up a /api/me URL that returns 401 or 200 depending on if the session cookie was sent. The problem with this is that this will leave the frontend in a limbo while the request is resolving.
Make the cookie not https only. However, I've read online that this makes it vulnerable to XSS attacks.
Send a second, non https only cookie as well to show that the session cookie exists. If this cookie is tampered with the worst that can happen is that a user will receive a 401 error later down the road when they make an API call without the session cookie.
Put something in local storage or in a cookie before the request to signify a user hit log in and check for it on page load. However, I won't know if the login succeeded or not.
Create a second page specifically for unsigned in users on the / route. Then, the callback can redirect to /signed-in. However, how will my /signed-in route know if a user navigated there or if the server redirected them? (ex. if the user autocomplete's the browser bar to the /signed-in route after their session expires)
Out of all these the third approach seems the most viable (the second cookie). However, this seems like a very trivial problem that someone has solved before. What am I missing here?
Note: I don't want to use ssr here. If I was using ssr I could simply just check for the session cookie server-side on the / route and reply with a different HTML template.
Edit: I could combine ideas 3 and 4. Put something in a store before sign in. If sign in fails, have my server redirect to a /fail page. If not, redirect to /. Then, / can reload the store on page load. /fail would also delete the stored item so that a user who failed can't just immediately go back to / and see they are logged in. The only unauthorized people who would see my user ui on / would be
Users who close out of the page during their login (never finish their login so never redirected to /fail to delete the store)
Users who revoke their OAuth token. This will have to be caught later down the road when my server receives a 401.
I could also add in a third "authorizing" state. I would set this before login. On page load with the authorizing state, I'd make a request in the background to validate that the user finished signing in. If I get a 401 from my server I'd have to move the user out of the authorized page. It wouldn't be nice but it'd occur less often than if I didn't use the store.
Before hitting sign in set a temporary loading value inside a store (cookie, framework store, localstorage, etc).
If the callback URL receives a failure value, redirect to the /fail route. /fail will set a failure value inside the store and redirect to /.
If the callback URl receives a success value, redirect to the /success route. /success will replace the temporary value with a success value.
On page load, read the store.
If the store is empty its a new user.
If the store has a temporary value, they never get redirected after the callback. Show a toast about an error and then display the sign in page.
If the store has a failure value, they failed the OAuth. Again, show a toast and display the sign in page.
If the store has a success value, everything went right. Show the user UI.
Eventually, the user may want to revoke their token. If they do, my app will not know until I make a request to a protected api endpoint with their token. If so, just pass the 401 to my frontend. I can show a modal saying they are unauthorized and then replace the success store value with an empty value.

Preventing multiple simultaneous logins with Cognito

We have React Native app that uses Cognito for authentication. We would like to prevent the same user ID from logging in simultaneously from multiple devices.
We were hopefully that we could use a Cognito pre-authentication trigger for this. Unfortunately it seems that we can't just call globalSignOut for the user since that wouldn't invalidate tokens that have already been issued and are currently active (see https://github.com/amazon-archives/amazon-cognito-identity-js/issues/21#issuecomment-331472144).
The other idea was to reject the login if the user is logged in elsewhere. But we can't see a reliable way to tell whether the user is already logged in. We can see if there are valid tokens issued for that user but not if they are currently associated with an active session.
We also thought of maintaining our own DB of active sessions but there is no sign-out trigger so we wouldn't know when to remove a session from the DB.
You can use a token authentication system,
Issue a brand new token for each login, and check for available tokens.
if any token is available for the user that means He/She is logged in some other device, for this case you can prompt user that You are logged in other device.. are you sure you want to log out from that device ? and after clicking yes, you can clear all tokens for that user. And issue a brand new token.
AUTO LOGOUT : this token should be passed all over the back-end i.e. in headers of each and every API call token should be there... and should be checked before doing anything in back-end. if token is not available then throw 401. In your app if any API throws 401 then it means user is UNAUTHORIZED and should be logged out.
or
your app should be listening to one socket that responds to log out when it receives a message of same. so whenever your user logs in, a logout message will be passed across sockets and appropriate device with some token id or unique id will get that message and will log out a particular user from all other devices.
or
have a notification receiver which will be used to log out whenever necessary same as socket.
Reading the link you provided the API token / session system seems being faulty by design since long time already.
So without an own token-system inside cognito you won't have reliable results probably, at least in the current state of the system (as the repository is archived it won't be developed further by the owner).
What I propose is an own field in the database-table for users where each login is honored with an own token. A second own field in the same table with a timestamp, where the last access is saved.
If last access is older than a predefined time of 30, 60 or 120 minutes any user gets logged out.
If the last access is younger than the time-limit then the login-mask has to provide a random access token which is compared with that in the database:
- if the access-token in the database is too old for an active session, or just no access-token is stored, then access can be granted which means login is successful.
- the comparison of the current time with the time-stamp saved in the database is for cases where users never have been logged out by purpose but just by being disconnected or passive. I think this case will happen regularly, so it's no exception.
- logging out by click on a button should destroy the access-token in the database, so that the user can immediately login from any device, even from another one then before.
- if there exists a valid access-token in the database then no new access will be granted and the user should get shown a message that he has to sign out first at another login.
- The access-token could be stored together with a third own field for the session-id to make it more reliable and safe. On logout that session-token-field can be cleared too. The session-token can be copied from the global session if required to be saved in the user-record.
- Any checks are only done on login, tokens never have to be included on every page.
- On active logout the token(s) have to be destroyed to allow a direct login again, else the users had to wait till the max. age of the time-limit is reached to login again - at least on another device then before.
As the login itself is currently done independent from the check that has to be implemented, it would be possible to leave the new access-token completely away but use only the session-id as that differs on any device and browser. But perhaps there exists a situation where one of session-id and access-token can change but the other one not - I don't think so but perhaps I missed something in my considerations.
If you provide the access-token on every page like proposed by #Jadeep Galani or in a cookie - beside the corresponding check - you also can offer a button to sign out from all devices. This would enable the users to change login any time even without logging out at the last used device. Without access-token on every page or in a cookie this general logout-function solution is not possible as else access is only checked on login but not on all pages.
A general question is if it's still worth it to rely on the buggy cognito for login or just replace it completely by an own solution. You even could implement the desired authentication in your site in form of a wrapper-class and the concrete login-system could be replaced without changing that implementation.
You can use the UUID of the device to identify whether it is the same user. Add a UUID to each request header to record it in the DB, and then you can do what you want.

Security of storing Bearer token in cookies

My SPA uses React as front end and laravel API as backend.
When the user logs in (via axios and api), the api returns an access (Bearer token) as response. I use the react-cookie framework to store the access token as cookie in the Browser. This cookie will be read and used for any future request.
Is this the right way to do?
Isn't cookie data just something in the Browser that can be easily obtained by any attacker? Since it is just a file one the computer somewhere.
What is stopping an attacker from grabbing that cookie, impersonate as that user and start performing actions that requires authentication?
The token has a life span of lets say 1 year. It will only be refreshed every time the user logs in. I understand that if I set the life span shorter it will be more secure. However that will mean the user would have to log in constantly?
-----Update-----
Im not sure if any of the provided solution answered my question. A SPA app is front end based and the request can be from anywhere such as Postman, Mobile app, or any third party device that wish to talk to my backed server. So those device needs a way to store some access token locally to be used for any future request.
The only way I know this could happen is for my server to send some auth token to the requester and have it store it somewhere to be used for next request.
In this case, Im not sure if CSRF token or any other means would help my concern?
Just like facebook, if I clear my cache, I will have to re-login. That means facebook is storing something on my location computer so I can be automatically authenticated next time
I just want to add some disadvantages of storing tokens in cookies that you should also be aware of:
The max size of a cookie is only 4kb so that may be problematic if
you have many claims attached to the token.
Cookies can be vulnerable to cross-site request forgery (CSRF or
XSRF) attacks. Using a web app framework’s CSRF protection makes
cookies a secure option for storing a JWT. CSRF can also be partially
prevented by checking the HTTP Referer and Origin header. You can
also set the SameSite=strict cookie flag to prevent CSRF attacks.
Can be difficult to implement if the application requires
cross-domain access. Cookies have additional properties (Domain/Path)
that can be modified to allow you to specify where the cookie is
allowed to be sent.
------- Update -----
You can also use cookies to store the auth token, even it is better (at least in my opinion than using local storage, or some session middleware like Redis). And there are some different ways to control the lifetime of a cookie if we put aside the httpOnly and the secure flags:
Cookies can be destroyed after the browser is closed (session
cookies).
Implement a server-side check (typically done for you by
the web framework in use), and you could implement expiration or sliding window expiration.
Cookies can be persistent (not destroyed
after the browser is closed) with an expiration.
Your JS should not have access to the cookie. There are flags you can set on cookies that will help protect them and make sure they are only used for the correct purposes.
The HttpOnly flag is set on the cookie then JS will not be able to access it but it will still be sent with any request.
The SameSite flag will ensure that the cookie is only sent back to the site that gave it to you. Which prevents leakage.
The Secure flag will make it only send the cookie over a secured connection to prevent someone from sniffing it out of your web traffic.
Edit
You might want to lookup an authorization workflow but the gist of it is this:
User logs in with username and password
A JSON web token is issued upon login from the backend and sent to the browser
The JWT(JSON web token) can be stored in a cookie in the Web Storage(Session Storage) on the browser
Subsequent requests to the REST API will have the token embedded in the header or query string for authorization. With that form of authorization, your REST API understands who is making the request and what kind of resource to return based on the level of authorization
Please see #tpopov answer as he also made some really good points.

Detecting user logout on browser close in Django

we have a web service for some numerical computing. It has a registered mode, in which a user has to register to have its results sent by mail.
We would like to keep track of how long the user stays logged. The login time is written in the database upon successful registration. Registration in not permanent, it's just for the purpose of single session and is used for acquiring the user email.
There are a few situations possible:
User logs out normally via the logout button.
Simplest solution. Write the time and logout in the database, and delete session.
User logs out by session expiry.
I'm planning on having a script which would check all the database entries which don't have a set logout time and if current time - login time > expiry time write logout time in a database as login time + expiry time.
User logs out by browser close.
The sessions have a get_expire_at_browser_close() set to True. But i don't know how can the server detect browser closure.
Ideas, critics, comments?
In django session middleware these lines control session expiration if we want that SESSION_EXPIRE_AT_BROWSER_CLOSE:
if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
max_age = None
expires = None
Server doesn't have to do detect anything as cookie that has no max_age or expires set should be deleted on the client side, according to this page:
By setting either of these, the cookie will persist until its time runs out, otherwise—if you set neither—the cookie will last until you close your browser (a “session cookie”).
Edit:
One way of tracking how long user was online is by using javascript that will ping server every now and then. It will happen only as long as the user has page opened in browser and on every ping server should update last seen online value for the user.
When user closes browser session is over. Next time user logs in server can calculate duration of his last visit as last seen online - last login time.
Simpler solution without using any javascript: last seen online could be updated on every user request using simple custom middleware.

Django key based session expiration

I have a website which contains several rule sets for different kind of users.
One of the rules (permission) depends on the session expiration.
For instance, an unauthenticated users' session must be flushed when browser is closed however, authenticated users' sessions should live for a constant time.
Furthermore, for authenticated users some keys in the session may be deleted when the browser is closed but other should be kept alive.
How can I achieve this key-based session expiration in Django ?
You can do this by using the set_expiry method on request.session. The method takes either an integer for number of seconds to expire the session, a datetime or timedelta for when the session should expire, the integer 0 to indicate the session should expire at browser close time or None to indicate that the session should fall-back to the default timeout policy.
You should be able to write a piece of middleware that evaluates the criteria you have for session expiration then call set_expiry on the session before processing the request.