Where should I refresh my JWT in SvelteKit - jwt

I'm trying to implement JWT authentication in a SvelteKit-app and I'm having trouble with where in the code I should refresh my accesstoken on site-reload.
According to what I have found I should store the JWT in memory and then have a refresh-token that is stored as a HTTP-only cookie. When the page is reloaded or opened in a new tab, I need to call my backend to see if the refresh-token is valid or not, if it is, I will generate a new JWT and return it to the client.
Where is a good idea to make this call? I was thinking that the getSession-hook would be a good place but I'm not able to use fetch from there.

HTTP-only cookies must be set via the Set-Cookie header. SvelteKit only has a few places where you can set response headers:
Svelte Endpoints
The handle() hook.
getSession() is probably not a good choice. The main purpose of this hook is create a sanitized version of the server context for the browser (like remove sensitive information like passwords/API keys.) It is called after the handle() hook, so it would be too late for setting any headers in the response.
getContext() may be a better choice because it is called before the handle() hook. So it is possible to get the refresh token and store it in the context until handle() sends it as a header. The context is accessible from handle() as request.context
Although not well-documented, fetch is available from all of these hooks. Simply add node-fetch as a dependency in package.json (not a devDependency!).
I think a problem with refreshing the token in the hooks is refreshing will happen on every request. This may add unnecessary overhead to your app.
I think the best solution is to wrap any API calls that need JWT tokens as SvelteKit endpoints. If the API call fails due to a stale token, the endpoint can get a new token and send it to the browser via Set-Cookie in the response headers. Note for this to work, you must ensure the endpoint is being called by the browser (not the server.) SvelteKit templates are executed first on the server, then again in the browser. If the endpoint is called from the server, the browser cookie will not be set.

Related

JWT default GET action limitation?

I've successfully used cookies before and I'd like to begin using JWT. My biggest question is how to pass your token to a website during the initial GET operation, for example when a user types your domain into their address bar or clicks on a link from some other website like google.
When using cookies for example, if you type stackoverflow.com into your web browser, the persistent cookie is sent to the website which seamlessly allows your own stackoverflow session to be automatically authorized.
I am aware that I can programatically pass my JWT token via a javascript GET through the HTTP headers but how do you pass the token when a visitor types in your URL into their web browser?
Possible solution #1
My thoughts have been to have javascript code check if 'authorized'. If not, check for a JWT token in local storage. If found, redirect to the same address. The problem of course would be that there is no way to pass the token during a redirect.
Possible solution #2
Similar to above but not issuing a redirect, I would update the current page to reflect the 'authorized' state.
Possible solution #3
Use a permanent cookie containing the JWT token. I am thinking that this 3rd option would be the best. If I did this, there would be no need to pass the JWT via an HTTP header.
I've thought about this for a few days, read up on JWT and here are my conclusions for avoiding JWT in my particular case:
No easy way to authorize a user who opens their browser and types in your website. With cookies, your server immediately knows how to respond to this headerless GET request.
No way to easily change the JWT token signature. All users are immediately affected by such a change, essentially forcing everyone to authenticate again.
No way to easily invalidate a specific JWT token. The best you can do is to maintain and check a banned signature list on the server. This of course would require a centralized or distributed server method almost identical to a cookie session management system. This would force a coupling between the token and the server, no longer stateless as intended by JWT.
SUMMARY
Cookie management requires more server infrastructure but you have much greater session control. State is seamless (in the case of #1 above). You can instantly invalidate state. For example, the user can log out (deleting the session at the server level) or the session can be instantly banned by an administrator by simply deleting the session.
I also see the benefits to JWS:
no need to hit the db or cache system when authorizing.
simple authorization between multiple servers having the secret key.
simple authorization, no session management programming and no db session state storage required.
...but the drawbacks stated previously are too great for my particular needs.

Can I use the access token directly from FB.login on my server?

I'd like to implement a Facebook authentication that does not perform traditional oauth redirects. It doesn't play nicely with my single-page-application and GraphQL API.
On the JS side, I can invoke FB.login to trigger a dialog for the user to login. If this is successful, I receive an object containing an accessToken and a signedRequest.
signedRequest can be decoded on the server and it spits out a code for me. I can use code with /oauth/access_token to get an accessToken.
However, I already had the accessToken this whole time from the FB.login response. So my question is: is there any point of me decoding the signed request, if I had the access token this whole time?
Bonus: Why does the FB API provide a signed request in the first place, and why does the oauth redirect by default forward the code and not an accessToken?
Yes, you can use the token you got from the client-side login, directly on the server.
It might however be a short-lived one, whereas the server-side login flow should give you a long-lived one right away. If you only need to perform API calls while the user is active on your page, the short-lived one will probably do. (And it could still be exchanged for a long-lived one with a server-side API call, https://developers.facebook.com/docs/facebook-login/access-tokens/refreshing)
Why does the FB API provide a signed request in the first place
It also contains a bit more info, that might be useful for a client-side app (user id, token expiry, externally passed in data in case of the old “Canvas” type apps), and might save on one additional API call to get that kind of info. https://developers.facebook.com/docs/reference/login/signed-request/
and why does the oauth redirect by default forward the code and not an accessToken?
General security measure. The token contained directly in the return URL, could easily be stolen by 3rd-party scripts that might be embedded on that page (ad servers etc. can get hacked from time to time, too), or leaked as part of the HTTP referrer.
The code parameter requires your app secret for the API call that exchanges it for a token, so if the code were to leak in any such way, whoever else got their hands on it, can’t do anything with it.

How to prevent CSRF in API-Centric Web Application

I am looking to build a web application using API-Centric architecture.
The frontend of the application would make requests to the REST API using AJAX.
The API is also used by other clients for various purposes. I'm of the opinion that the use of CSRF tokens may not be applicable to their implementation.
Other approaches include verifying the origin in the headers, but of course, headers can easily be spoofed.
How could I implement a robust CSRF prevention strategy for this application?
Some proposition: First You can use api-url like GET api/gime-csrf which return CSRF token as response and also set it in http-only cookie (so JS has no access to it - but remember to block TRACE request in server to prevent XST attack). Then when you make some "save state" request like POST/PUT/PATCH - you just put CSRF in some request header - and in server you compare header token value with cookie token value.

How to download a file secured with IdentityServer

I want to be able to download a file from an API call. For argument's sake, let's say it's an automagically generated PDF file.
I have two problems:
Anchor tags can't add Authorization headers to the request, only XHR can.
XHR requests cannot download files.
My solution is to write my API with an [AllowAnonymous] end point in it, which takes the access_token as a parameter. I then validate the access token by hand and return a 401 or stream the PDF.
Is there a better solution than this or, if this is the best solution, how do I validate the access_token within the API?
This approach is totally fine.
If you want to use middleware to validate the token - it depends which middleware you are using. The plain Microsoft JWT bearer middleware has some events you can implement to retrieve the token from a query string alternatively.
The identity server token validation middleware has a TokenRetriever property which also allows you to retrieve the tokens from multiple/alternative locations.

How to set a authenticated user web session for sending rest requests

I want to test an API which has the followoing instruction:
This API requires the caller to have an authenticated user web session.
When I login to the application and send a GET request in other tab it works. But I want to send a PUT request now so I cannot use browser. How can I have an authenticated user session while sending request through some other rest client. For eg: postman/ mozilla rest client.
I have tried logging into application through chrome and then using postman rest client. But it did not work. I have also tried Basic authentication providing application username and password.
So, given you mentioned you're using JWT, your API is most likely handing out this token upon logging in. At this moment your web client (javascript?) is probably storing it somewhere (cookie, local storage, session storage… – you can use your browser's dev tools to inspect). For all subsequent requests, this token is attached. If this token is getting persisted as a cookie, the browser itself takes care of attaching it to every request. If it is persisted somewhere else, your client has to "manually" attach this token to every request.
If you want to test your API call, first you need to login and get your hands on the token. Then, for all authenticated requests, you need to attach this token (probably as the Authorization HTTP header).