Hello! This is my attempt at providing an example on how to use Remix
(an amazing tool for building SSR web applications in React) with SuperTokens
(an open source alternative to user authentication). Note that this repository uses the EmailPassword
recipe/approach from SuperTokens
for its examples. However, the code here should be easily transferrable to the other authentication repices/methods that SuperTokens
provides.
Note that this application takes an SSR-only approach for three reasons: 1) Better security (big plus), 2) Guaranteed progressive enhancement (also a big plus), and 3) Easier code management (arguably).
If there are any questions, concerns, or ideas for improvement, feel free to reach out to me in the SuperTokens Discord or the Remix Discord. (Technically either one works. But if your question is more oriented towards SuperTokens, you should probably ping me on the SuperTokens Discord.)
npm run sass
.
Remix
only reads CSS
files, not SCSS
files; so Remix
needs compiled CSS files that it can reference.npm run dev
.
.env
file to configure SuperTokens! You will need to configure:
DOMAIN
(e.g., http://localhost:3000
)SUPERTOKENS_CONNECTION_URI
(e.g., https://try.supertokens.com
)SUPERTOKENS_API_KEY
(optional if your SUPERTOKENS_CONNECTION_URI
is https://try.supertokens.com
)SUPERTOKENS_WEBSITE_DOMAIN
(e.g., http://localhost:3000
)SUPERTOKENS_API_DOMAIN
(e.g., http://localhost:3000
)SUPERTOKENS_API_BASE_PATH
(e.g., /auth
)This project uses ESM by default. (This was accomplished by setting type
to "module"
in the package.json
file.) Unfortunately, this creates some complications. In short, all import
s that will be handled by Node.js -- whether in transpiled files or in untranspiled files -- need to follow the rules that Node.js provides for ESM imports. Some examples:
/server.js
file is pure JS. It is not transpiled, and it is run directly by Node. Therefore, it must properly include the .js
file extension for relative imports.index.server.ts
(post transpilation). Node.js cannot understand import Session from "supertokens-node/recipe/session"
when using ESM, and Remix does not transpile this import since it comes from node_modules
. Therefore, you must change it to import Session from "supertokens-node/recipe/session/index.js"
for Node's sake.We've already taken care of this for you in our project. However, you should keep this in mind when extending this project with your own code.
(Some additional context: https://discord.com/channels/770287896669978684/1194003027695247391/1194003027695247391)
There seems to have been some controversy surrounding the new file routing convention in Remix v2. Due to its (subjectively) unappealing look to the maintainers, we are using the old file routing convention. However, you are more than welcome to use Remix's new system by removing the customization! Because this project doesn't use any directories for file routing, you will not experience any significant differences between either routing convention (assuming you haven't extended the project yet).
For what it's worth, the well-known web developer, Kent C. Dodds, has chosen to go with a convention crafted by Kiliman. It seems favorable, and this project may very well incorporate it in the future.
There are a few reasons why a custom UI was used in this repository (instead of what SuperTokens provides for the React). To give just a few...
[^1]: Almost certainly, these concerns with the components provided by SuperTokens will be resolved in the future. (Part of the point of this repo is to give potential improvement ideas.)
supertokens-website
or supertokens-web-js
?Depending too much on supertokens-website
or supertokens-web-js
will result in an application that cannot run without JavaScript. And an application that can't run without JavaScript is actually inaccessible to a lot of users. Consequently, we've pursued a solution that works without these pacakages and without JavaScript. (Don't worry! We still enhance the app with JS to improve the user's experience whenever possible.) This means that our application will be accessible to the broadest range of users! :smile:
As an added bonus, we decrease our JS bundle size when we avoid the use of supertokens-website
and especially supertokens-web-js
.
supertokens-node
?If you've seen the comments from @Rich-Harris (creator of Svelte) regarding server middleware (e.g., Express Middleware), then you'll know that solutions which require you to use middleware are often restricted and will prevent you from enhancing your application with other very important features. This is especially true if you're working with an SSR framework. Unfortunately, I have found Rich Harris's statements to be correct while working with my own Svelte Kit application. There are workarounds for these problem cases that allow people to still use middleware... but those aggressive workarounds often end up looking more ugly and complicated. (And thus, such approachs are more prone to error).
Avoiding the supertokens-node
middleware ended up being required for me to use HTTPS in my application and get it working with high security in Cloudflare. I'll spare you the details, but there are other edge cases like these where supertokens-node
middleware just won't work (or won't work well). Thankfully, in supertokens-node@14
, the SuperTokens team was kind enough to introduce functions that allow you to get authentication working without using their custom middleware. If you're using any kind of SSR framework that leverages progressive enhancement (SvelteKit, Remix, SolidStart, etc.), then you'll want to leverage these functions instead of using the middleware as well.
Although the middleware-free approach gives us many advantages when it comes to using SuperTokens with SSR frameworks, it also gives us a little more responsibility. You'll notice in this app that we have to be intentional about the settings which we use for our HTTP cookies. You don't necessarily need to use the settings that I have (though you should use HttpOnly
and you should set a strict Path
), but you should certainly ensure that your settings are the safest that they can be for your application. Here are some resources that may be helpful for you on the matter:
Set-Cookie
HTTP Header Workscookie
NPM package (Svelte Kit uses this under the hood to set the options for its cookies)It doesn't currently seem like Remix
provides any significant CSRF protection out of the box; so if you're interested in addressing the matter and you're willing to stay with Remix
(instead of trying out something else like SvelteKit
), consider the following resources:
SuperTokens does have some anti-CSRF features, but there are cases where it should be used and cases where it need not be used. From @rishabhpoddar:
Basically, when you call
createNewSessionWithoutRequestResponse
, and if you get an anti csrf token, then you should pass that in when usinggetSessionWithoutRequestResponse
. If you do not get an anti csrf token, you don't need it (based on yourapiDomain
andwebsiteDomain
setting) and should check for custom request header before callinggetSessionWithoutRequestResponse
. You should not explicitly set the value ofdisableAntiCsrf
when calling createNewSession unless you are not using cookies at all.
Bear in mind that if you're using a framework that (sufficiently) protects against CSRF by default, then you don't necessarily need to worry about the custom headers yourself.
I hope you find this useful! Let me know your thoughts here on GitHub or on their Discord. :) If there are any ways that I can improve anything here, feel free to say so.
Remix
README