Persistent user session using AWS Cognito in Electron - javascript

Making a AWS Cognito user session persistent in Electron
AWS Cognito stores the current user session in the localStorage. While the user session is present in localStorage after the user has logged in, localStorage isn't persistant in Electron - so when the application restarts, the user session is gone and the user has to log in again. Normally the user session would be recieved from localStorage, since it is persistent in browsers.
I know that one can use electron-json-storage to store data persistantly in Electron and generally in node applications, but since AWS cognito uses localStorage, I am only able to use an approach that would change localStorage into being persistant, i.e redirected to a file storage.
I have tried node-localstorage which works, but cognito still uses the localStorage from the browser, even when global.localStorage is set.
I know that the userPool can be passed a {Storage: ...} object to use that as storage, but it still used the original localStorage, when I passed the node-localstorage to it.
TLDR;
How can I make the AWS Cognito user session persistent in electron?
If possible, can I replace localStorage with node-localstorage globally, so that AWS Cognito will use it?

Cognito will be giving you three tokens idToken, accessToken and refreshToken
A simple idea will be to save the refreshToken in your localstorage that you think is persistence. and on electron app start use that refreshToken to authenticate user user on Cognito.

Related

How to Access Firebase's Authentication Persistence Manager Keys?

I am running a web app with Firebase redirect authentication.
When the user is returned to the web app, the web app initializes once more while the authentication redirect is pending.
This state can be seen in the browser session storage, like this:
{firebase:pendingRedirect:AIzaSyCMM24e1XAkOQD-wo_TnoaFNXFzFk93sj8:[DEFAULT]: '"true"'}
I want to retrieve this item in an idiomatic way. Right now I am using this util:
function getAuthRedirectIsPending() {
for (let i = 0; i < sessionStorage.length; i++) {
const key = sessionStorage.key(i)
if (
key?.startsWith('firebase:pendingRedirect') &&
sessionStorage.getItem(key) === '"true"'
) {
return true
}
}
return false
}
But I also noticed that this key exists on the firebase auth object, albeit inaccessible:
{
"persistenceManager": {
...
"fullUserKey": "firebase:authUser:AIzaSyCMM24e1XAkOQD-wo_TnoaFNXFzFk93sj8:[DEFAULT]",
"fullPersistenceKey": "firebase:persistence:AIzaSyCMM24e1XAkOQD-wo_TnoaFNXFzFk93sj8:[DEFAULT]"
}
I was wondering if there was a way to retrieve the persistence redirect key name from Firebase, then using it to access the window session storage?
Firebase Authentication Persistence Manager uses the Web Storage API to store user authentication tokens. The Web Storage API is a simple key-value storage system that provides two types of storage mechanisms: session storage and local storage.
The session storage is a temporary storage mechanism that is cleared when the user closes the browser window or tab, while the local storage persists even after the user closes the browser window or tab.
Firebase Authentication Persistence Manager stores the user authentication tokens in the local storage, and the keys for the local storage are accessible through the browser's developer console.
To access the Firebase Authentication Persistence Manager keys, follow these steps:
Open your web application in your browser and navigate to the authentication page.
Open the browser's developer console by pressing F12 or right-clicking on the page and selecting "Inspect."
In the developer console, select the "Application" tab.
In the "Application" tab, expand the "Local Storage" option.
Look for the Firebase Authentication Persistence Manager keys. The keys are named "firebase:authUser" followed by your Firebase project ID.
Click on the key to view the stored value, which will include the user's authentication token.
Note: Accessing the user authentication token may not be necessary in most cases, as Firebase Authentication provides methods to manage user authentication state without directly accessing the authentication token. Additionally, manipulating the authentication token can be dangerous and could compromise the security of your application.

Use refreshtoken from subdomain A to authenticate for subdomain B in Cognito

We are using Cognito via Amplify/Auth to handle our signup. After the signup is done (on signup.foo.com) we redirect the user to the dashboard (on app.foo.com).
Using localstorage, the session is locked to the domainname of signup.foo.com and not accessible at signup.foo.com.
We used cookieStorage with a *.foo.com domain, which worked, but we are having issues with the cookies disappearing on our mobile Webview solution, so I am looking at going back to the localstorage solution.
However, it seems to be impossible to carry over a session from one subdomain to the second, even if we use the same app client in Cognito.
I was able to get a new access token using the refresh token of the signup session using aws cognito-idp admin-initiate-auth via the command line, but I can't manually inject the refreshToken or accessToken in the localstorage with the correct key name.
The Auth module doesn't accept it, and it probably is because the domain is hashed into the refreshtoken.
Is there an official way to, either via Node and a valid refresh or JWT token, to get a new token that can be injected into subdomain B?
Cheers,
Mattijs

JWT refresh and access tokens

I use jwt tokens in my project. Long-lived refresh tokens to authenticate and short-lived access tokens for protected resources. The refresh token is saved in a http-only cookie to reduce the risk of xss attacks. The access tokens will be only stored in my vuex store of my frontend. Should I renew my refresh token if the user changes the password? I don't store refresh tokens in my database, because as I understood the the main purpose of jwts is that I can use cryptography to verify my incoming refresh token and do not have to look it up in my database (then I don't have to use jwts at all).
But how do I invalide an already sent refresh token e.g. on an other device or browser? If I don't use a database to store refresh tokens the token would be valid as long as the expiration time is. I appreciate any advice.
Since you don't store tokens in the database you can't invalidate them remotely. But there are some common practices to overcome this issue.
NOTE: These are not standards, Just a practice used by major
companies.
1. Store tokens in Cache Database (Not in the main DB)
Storing JWT tokens in the cache database such as Redis or Memcached will allow you to retrieve and verify the token much faster. To invalidate the token you just need to remove it from the cache.
2. Use short-lived access and refresh token
This is mentioned in a lot of Security Submits. Expert says to set a very short life (in minutes) to both access and refresh tokens. Also, exchange the refresh token every time you get a new access token. This renewing process can be happing in the background (maybe using workers). So you don't need to invalidate tokens, It will be invalidated automatically after a few mins.
Recommend you to watch this: https://www.youtube.com/watch?v=rCkDE2me_qk
Store your refresh tokens in a database, with enough context to create a new JWT token (also expiry date, allowed IPs/regions/browsers ...etc) this database will be used only by your Auth service, and only when managing auth (login, logout, refresh access token).
Storing JWT in a database introduces a single point of failure for your microservices (Assuming you are using this architecture), if you're storing JWTs somewhere it would be a simpler implementation to just use session IDs and data.
Give each JWT token an ID (it's already in the default claims), and link that ID to a refresh token
when you invalidate a refresh token, broadcast an event to all your services telling them that any JWT with the token.JwtId is invalid. this invalidates all JWTs created by that token on all services (You can invalidate by token context as well, ex: user id to invalidate all tokens for a user that were created before X)

AWS Cognito Identity Pool: AWS Credentials Expiration / Renewal

I'm building an AWS-backed site which, broadly speaking, does the following:
Authenticates a user against a Cognito User Pool (the pool is backed by a third-party SAML provider), giving them tokens.
Uses a Cognito Identity Pool to grant the user credentials for use with other services.
Lets the user perform a series of long-running S3 uploads, directly from the front-end S3 client, using the credentials from above.
I'm trying to get clarity on the interactions I will have to have with tokens and credentials. I'm pretty clear on what I have to do with the tokens I get from the user pool:
I can use them to call the Identity Pool, and get AWS credentials I can use for S3.
I can use the refresh token to refresh the other tokens if they expire before I'm done.
The expiration details for these tokens are in the link above. The documentation is pretty clear on all of the above, but I'm confused about the Identity Pool credential functionality, and haven't been able to find explanations in the docs on the following questions:
When I get AWS credentials from my Identity Pool, how long will they last before expiring? How can I configure this value, so that my CognitoIdentityCredentials gives me credentials with my desired expiration?
If my AWS credentials expire before I'm done with my work, what's the right logic for attempting to 1. refresh the credentials and 2. if that fails, refresh the user pool tokens, so as to be able to complete the operation cleanly without making the user restart it?
The user pool is only for user management. Any interaction that the user has with AWS services and resources is done via Identity Pool. You assign the roles via Identity pool.
To answer your 2 specific questions:
Tokens last for 1 hour. This duration is fixed and cannot be changed.
If your tokens expire you can use the refresh token to generate new identity and access tokens. However, most of the front end sdks (even javascript) do this automatically for you. You don't have to worry about tokens expiring. In fact you will have to forcefully invalidate them if you have that requirement.

Avoid local storage restore

I have a Vue SPA app+ Spring boot services that use token + session cookies solution to handle user sessions.
If a user logs into service A, it sets a cookie Ca in the browser and service B uses this cookie to send a request to service A, verify the cookie and obtain a temporary token(which would be used by service B for subsequent requests).
This token is stored in the local storage. Local storage and cookies will be cleared upon user logout.
But if a user presses the browser back button after logging out, the local storage gets restored and users can still consume services with the token.
Is there a way to permanently clear the local storage to prevent this?

Categories