How to store generated api keys in React? - reactjs

If a user logs in with user and password, he gets an new api key,
so react can access the Rest Api with his user account. How do you save this api key? And what happend if the user clicks 'refresh page'?
Of course I can initalize the Rest App every time with
<script>
window.REP_LOG_API_KEY = '19e8317a38b24af82da056f6ed36e831ea6b8f9bfcad996aaa56ec773f9f2e1d';
</script>
<script src="build/reactapp.js"></script>
but dont look very secure (but I like the idea of changing this key
every page request, if you have no single page application and react
is only used here and there).
To store the Api Key in a cookie would be also possible (secure but not
httponly, normally I only use safe cookies). Is this the only way?
I'm still not quite sure how to use react with a rest api
with individual api keys. Thany you.

The API key you are talking about is probably cookies/authentication token. If it is cookies, you need to enable httpOnly to prevent attacks. For authentication token, the most common way to store is in localStorage or sessionStorage. However, it is insecure, even with HTTPS and short expiry dates (and you do HAVE to use them). Putting it in Redux store is the same as putting it in a global js object where everyone can see.
What will protect your app is to check standard headers to verify the request is same origin (source and target origins check) and CSRF token. Also a common pattern is to verify the token signature before storing and using it. You can check out Auth0 blog on where to store it here: https://auth0.com/docs/security/store-tokens

There are several ways to do this. If you are using a state management library like Redux, MobX, Flux etc, then you can put it there.
Another place to store them is in the browser local storage. This will keep the token saved even if the user refreshes the page or open a new tab etc. Yet I am not 100% sure whether it's a safe thing to do.
Or you can attach it to the Rest Client itself. IMO, this is the best way to do it. I will summarize the steps to do that in brief.
Create a Rest Client by wrapping a solution like fetch-api or axios.
Add a module state, where you can store any data
Whenever making a call, check if there is a token, if a token is not there in the state, then authenticate first.
If the token is there, use it to make the api call. If the request fails with a 403(or may be 401. It depends) error, that means the token has possibly expired. So authenticate again and update the token.
Something like this,
class ApiClient {
constructor() {
this.token = null;
}
login(username, password) {
// make the call to login
// set this.token with the response
}
request() {
// Make the API call using the token
}
}
What will happen with a refresh? Then since the token is not there, the authentication will need to happen again. This will not be a problem if you use cookies to manage sessions.

You can put it in Redux store. I think it is the best implementation.

Related

How to ensure RTK Query does not cache certain endpoints which take sensitive data?

I have an endpoint for authenticating the user, which takes the user's username and password. The request returns a token which the app should then use for all subsequent requests, so I store it in the Redux store.
The tokens have a limited lifetime, so the app has to get a new token every so often. Because of this, I want to store the username and password using the device's secure chain storage (I'm using React Native), not on the Redux store, since doing so make it easy to extract the credentials from the app memory.
But since RTK Query by default caches requests based on the args passed to it, the user credentials will be cached in the Redux store.
So my question is two-fold:
Is what I'm saying even sensible? Does the logic for how I want this to work makes sense?
If yes, then how do I go about disabling the cache for one specific endpoint for RTK Query?
The point of RTK Query is to put things into a Redux store. That is the core mechanism for everything.
You can do all the requests without it, but if you do a request with it, it will be cached, at least for a while.
That generally would not be much of a concern since a Redux store is just a variable like const foo = "somethingSecret" though.
That said, you should probably not store username and password, but a "refresh token" that you get from your server.
And usually, you should not store that yourself, but your fetch implementation should do that for you - in the form of a cookie.
This also works in React Native.
Your server just sets the cookie for both the token and the refresh token as a httpOnly cookie and you cannot even access them from JavaScript. In JS, you just say credential: "include" and all your requests to that same domain will contain those tokens.
Manually handling those tokens if you can avoid it is always bad security practice.

Is it safe to save jwt accessToken on session in Next.js next-auth? Then using useSession hook to access it on client side?

I'm using next-auth for authentication and using the Credentials provider for logging in, my API returns an object containing an accessToken like this object:
{ "token" : "UzI1NiIsInR5cCI..." },
And I'm returning a similar object containing the token in authorize property of CredentialsProviders while my session callback looks like this:
session({ session, token }) {
session.data = {
...session.user,
...token.user,
};
session.accessToken = token.accessToken;
return session;
}
And I use the useSession hook in my client code like this:
const { data: session, status } = useSession();
to access the user's token to make API requests.
Is this safe? Or is there another ways to achieve this?
Keep in mind that this application is gonna be fully client side rendered despite the fact that I'm using Next.js, so keep that in mind. I'm asking this because most of the docs of Next.js is SSR focused.
Quite often, we use localStorage to store the token after authorization, of course, since localStorage is the browser api, this means that we store the token on the client, which is actually similar to your case. I don't see much of a security issue with this, although it does make the token vulnerable to XSS attacks, so cookies are considered a safer way to store the token, since it can't be retrieved from the script side (if you set the http-only cookie option).
If you're worried, you can put the token in cookies to be sure. Although even so, the way to use this token for malicious purposes. The best way is to protect yourself from XSS attacks and then there will be nothing to worry about, react (well, including next) out of the box has good protection mechanisms.
In general, since we are talking about an access token, this is the thing that identifies the user and this should not be a problem for you to use it into the client, you should be more careful with the secrets of the application, such as the secret that is used to encrypt the token, then there will be security problems if you give access to it by client.
If you still don't want to use a token on the client side, which you probably don't need, you can use getSession on the server side for authorized requests with nextjs and proxy your requests through next to backend, using next as api is also a common practice.
To summarize, since you are using the next-auth library, you have nothing to worry about, since it takes care of most of the security concerns.
https://next-auth.js.org/getting-started/introduction#secure-by-default

MSAL - No Tokens Available when Using IneractionType.Redirect

In our application, we authenticate users using AAD, but we authorize users using our own User and Role tables in our local SQL database.
With the old ADAL library, we were able to return users to our callback url, then from there we would grab the JWT token from the ADAL service, and send that token to our server. The server would then validate the token, decode it and grab the email address. We then used our SQL tables to return another JWT that contained the user's identity and all of their roles.
With MSAL, this still works if you use InteractionType.Popup. The response Observable from the loginPopup() method carries the AuthentiationResult, which has an idToken property and an accessToken property. You can easily grab the one you need and you're off to the races.
However, with InteractionType.Redirect we don't get the AuthenticationResult.
I have injected the msalService instance into the our callbackURL's component (called AuthCallbackComponent). I looked everywhere within the msalService for the tokens, but couldn't find them. I even looked in sessionStorage, where I've configured MSAL to cache the token. They are actually in there (under a couple of really funky keys), but not until later. Whether I use ngOnInit, ngAfterViewInit or ngAftercontentInit, the tokens are not there yet. It does work if I set a timeout of 1-2 seconds, but...no. You can never really rely on timeout delays being long enough for all of your users all the time.
We desire to use the Redirect workflow rather than the popup workflow, so it really would be ideal if we can just get the idToken from the MSAL instance.
I found this post here: Retrieve token using msal, which offers some possible solutions, but the suggestions aren't helpful. It talks about a custom MSAL Interceptor, but that seems wrong. That's typically the HTTP interceptor that adds your token to the headers of your service calls. It also says you can subscribe to the callback and "do something with the returned token", but assuming they mean the callback of the msalService.loginRedirect() method, well that is just wrong. It doesn't return anything at all.
Remember, that in the old ADAL library, this worked. Also it still works with InteractionType.Popup (which we can't use). I expect those tokens must be in the MSAL instance somewhere, or else there's a method we can override, a callback we can provide, etc.
Thanks for reading this longer post.
Buried deep within the 10K pages of Microsoft documntation on MSAL, I found this event reference:
https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/v2-docs/events.md#the-inprogress-observable
So I used their example code to come up with my solution, which was to inject the msalBroadcastService into my AuthCallbackComponent. There I subscribe to its msalSubject$, and when a LOGIN_SUCCESS event happens, I can get the accessToken and idToken from the event's payload. Here is some code:
ngOnInit(): void {
this.msalBroadcastService.msalSubject$.pipe(filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS)).subscribe(msg => {
const idToken = (msg.payload as any).idToken;
// now I can call my service method, passing in the idToken
}

What is the best way to store an admin API token in Next.js ? Feel like storing it client side as http only cookie is risky

I'm working on a e-commerce using next.js and sylius API and the API admin routes are secured using JWT. So in order to fetch products (for example), i need to login to the API, get the token and then fetch the products using the token. The most common method to be able to send the token on every new requests to the API is to store it in a HTTP-only cookie.
As the pages are generated statically, i feel i don't need (and want) to expose the API token to the client. So i'm wondering the best way to store the token ?
Here the different options i have in mind right now:
store the token as a http only cookie and use it server side (with a proxy using next js API pages) in order to call the sylius API. Like i said, i'm not confortable to store the API token into the client, it seems risky to me, as it will be exposed to everyone, and with that token you can access the admin API.
configure the API in order to prevent the token from expiring, and store it in the next js app as an environnement variable (.env.local), so that it's not exposed to the client and can be used for fetching the api when generating static pages. The official ecommerce theme of Next.Js seems to use that method (https://github.com/vercel/commerce/blob/f770ad7a91059a2ecfbb9de1bac111dfe7016124/framework/bigcommerce/api/index.ts#L82)
store the token somewhere in the next js structure but not as an environnement variable (maybe a config file?), so that it can be replaced if necessary (if the token expires etc).
get the token and store it in the react state as is it will be used once only for generating all static pages. On each build the token will be asked again by the API and then used for fetching the API for exporting the static pages with the content. It don't need to be saved more time than the building step.
For me the last option seems better but i feel i'm missing something there, i'm kinda new to next, so i'm not sure exactly if its a good solution.
Thanks :)
I get a great answer from a reddit user ("supermaguireray"), so i post it as an answer here:
"First of all, in any session management mechanism the correct information needs to live on the correct domains, what I mean is that your client can only have access to a identification information, but never to data used in the server, these can be applied to a server-side session, when a ID for the user data stored on the server is sent to the client (preferably encrypted), or in a JWT where a encrypted string is sent to the client (identification), and decrypted on the server (Data).
With that said, the only reason you should send the API token to the client is if you need to fetch data directly from a browser. Storing as a httpOnly cookie is the most secure way.
In case you only need the cookie fetch data to the next backend, to render your SSG or ISR pages, there is no need to send a cookie to the client. Just store the token in your server. I would store it as env variable. Use next.config.js->runtime-configuration.
Or, you can keep a expiration date for the token, and store the credentials, maybe even in a DynamoDB or FaunaDB app."

What's a secure way to store token & auth state?

Here's my scenario:
When a user logs in, an API call is made and if his credentials are valid, a token is returned. I need to store the authentication state (to keep the user logged in) and the token somewhere. The token will be used to make other API calls.
I've read these posts: 1, 2, 3 (and some others) which all seem to contradict each other; whether it's localStorage, cookies or JWT, all are being deemed as unsafe by different people. I have also read about react-redux too but I'm not sure about it.
For now I am completely lost on which solution best suits my needs since I am new to reactJs. So, what is the proper way to go on about this?
The most common practice is storing your token in cookie and set HttpOnly to true, so that any javascript code cannot read your token programmatically.
I suppose you are using axios as ajax client, you can make a request like this
axios.get('https://example.com/api', {
withCredentials: true
})
by doing this, axios will send your cookies to remote server automatically

Resources