diff --git a/boilerplate/fullstack/remix/README.md b/boilerplate/fullstack/remix/README.md
index a1622019..fc76dad0 100644
--- a/boilerplate/fullstack/remix/README.md
+++ b/boilerplate/fullstack/remix/README.md
@@ -1,10 +1,12 @@
-![SuperTokens banner](https://raw.githubusercontent.com/supertokens/supertokens-logo/master/images/Artboard%20%E2%80%93%2027%402x.png)
+# SuperTokens + Remix
-# SuperTokens with Remix
+A demo implementation of [SuperTokens](https://supertokens.com/) with [Remix](https://remix.run/).
-This demo app demonstrates how to integrate SuperTokens into a Remix application.
+## General Info
-Feautures:
+This project aims to demonstrate how to integrate SuperTokens into a Remix application. Its primary purpose is to serve as an educational tool, but it can also be used as a starting point for your own project.
+
+Features:
- Initializes SuperTokens with frontend and backend configurations
- Creates a frontend route to handle authentication-related tasks
@@ -12,25 +14,29 @@ Feautures:
- Protects frontend routes to ensure only authenticated users can access the dashboard
- Exposes the SuperTokens authentication APIs used by frontend widgets
-## Project structure & Parameters
+## Repo Structure
+
+### Source
```txt
-📦[your-app-name]
+📦
┣ 📂app
┃ ┣ 📂config
-┃ ┃ ┣ 📜appInfo.tsx
-┃ ┃ ┣ 📜backend.tsx
-┃ ┃ ┗ 📜frontend.tsx
+┃ ┃ ┣ 📜appInfo.tsx --> Includes information about your application reused throughout the app.
+┃ ┃ ┣ 📜backend.tsx --> Backend-related configuration, including settings for SuperTokens.
+┃ ┃ ┗ 📜frontend.tsx --> Frontend configuration, including settings for SuperTokens.
┃ ┣ 📂routes
-┃ ┃ ┣ 📜_index.tsx
-┃ ┃ ┣ 📜api.auth.$.tsx
-┃ ┃ ┗ 📜auth.$.tsx
+┃ ┃ ┣ 📜_index.tsx --> Public landing page - accessible regardless of auth state.
+┃ ┃ ┣ 📜dashboard._index.tsx --> Protected route only accessible to authenticated users.
+┃ ┃ ┣ 📜sessioninfo.$.tsx
+┃ ┃ ┣ 📜supertokens.$.tsx
+┃ ┃ ┗ 📜auth.$.tsx --> Deals with authentication routes or components using SuperTokens.
┃ ┣ 📜app.css
-┃ ┣ 📜entry.server.tsx
-┃ ┗ 📜root.tsx
+┃ ┣ 📜entry.server.tsx --> Entry point for server-side rendering (SSR) setup.
+┃ ┗ 📜root.tsx --> Root component of your application.
┣ 📂assets
┃ ┣ 📂fonts
-┃ ┣ 📂images
+┣ 📂images
┣ 📂test
┃ ┗ 📜basic.test.cjs
┣ 📜package.json
@@ -38,65 +44,81 @@ Feautures:
┗ 📜server.mjs
```
-Let's explore the important files:
+### Config
-| Directory/File | Description |
-| -------------------- | ----------------------------------------------------------------------------------------------- |
-| **app** | Contains configuration files and route files for your application. |
-| | **config** |
-| | Contains configuration files for your application. |
-| | `appInfo.tsx` : Includes information about your application reused throughout the app. |
-| | `backend.tsx` : Backend-related configuration, including settings for SuperTokens. |
-| | `frontend.tsx` : Frontend configuration, including settings for SuperTokens. |
-| | **routes** |
-| | Contains route files for your application. |
-| | `_index.tsx` : Represents the default route or landing page. |
-| | `api.auth.$.tsx` : Handles authentication-related API endpoints. |
-| | `auth.$.tsx` : Deals with authentication routes or components using SuperTokens. |
-| | `entry.server.tsx` : Entry point for server-side rendering (SSR) setup. |
-| | `root.tsx` : Root component of your application. |
-| **test** | Contains test files for your application. |
-| | `basic.test.cjs` : A basic test file, presumably for testing functionality in your application. |
-| **remix.config.mjs** | Remix configuration file containing settings for your Remix application. |
-| **server.mjs** | File responsible for server-side functionality. |
+#### Vite
-## Run application locally
+Remix uses Vite to compile your application. Everything available in the [Vite configuration docs](https://remix.run/docs/en/main/file-conventions/vite-config) is available to use here (refer to the `vite.config.ts` file). The only customization we've done is changing the port to `3000`.
-Follow the steps outlined below to run the application locally:
+#### SuperTokens
-1. Change directory to the **[your-app-name]** folder.
+The full configuration needed for SuperTokens (the frontend part) to work is in the `app/config` directory. This file will differ based on the [auth recipe](https://supertokens.com/docs/guides) you choose.
- ```shell
- cd your-app-name
- ```
+If you choose to use this as a starting point for your own project, you can further customize the options and config in the `app/config` directory. Refer to our [docs](https://supertokens.com/docs) (and make sure to choose the correct recipe) for more details.
-2. Run the application with the command below:
+## Application Flow
- ```shell
- npm run dev
- ```
+Remix is built on top of [React Router](https://reactrouter.com/). While you can configure routes via the ["routes" plugin option](https://remix.run/docs/en/main/file-conventions/vite-config#routes), most routes are created with the file system convention. Add a file, get a route.
-## How to use
+This Demo application consists of four main parts:
-### Using `create-supertokens-app`
+1. **Entry Point (`entry.server.tsx`)**
-- Run the following command
+ - Initializes the Remix application on the server-side
+ - Handles SuperTokens initialization on the server-side
-```bash
-npx create-supertokens-app@latest --frontend=remix
-```
+2. **Root Component (`root.tsx`)**
+
+ - Initializes the Remix application
+ - Wraps the application with necessary providers:
+ - `SuperTokensWrapper`: Manages auth state and session
+ - renders the `App` component
+ - unprotected routes are rendered without the SessionAuth wrapper
+ - protected routes are rendered with the SessionAuth wrapper
+
+3. **Home page (`/` route, `/routes/_index.tsx` component)**
+
+ - Public landing page accessible to all users
+ - Provides navigation to authentication and dashboard
+ - Displays basic application information and links
+
+4. **Auth (`/auth` route, `/routes/auth.&.tsx` component)**
+
+ - Renders the SuperTokens' pre-built auth UI
+
+5. **Dashboard page (`/dashboard` route, `/routes/dashboard._index.tsx` component)**
+ - Protected route only accessible to authenticated users
+ - Protected by `SessionAuth` component
+ - Displays user information and session details
+ - Provides functionality to:
+ - View user ID
+ - Call test API endpoints
+ - Access documentation
+ - Sign out
+
+When a user visits the application, they start at the home page (`/`). They can choose to authenticate through the `/auth` route, and once authenticated, they gain access to the protected dashboard. The session state is managed throughout the application using SuperTokens' session management.
+
+## Customizations
+
+If you want to customize the default auth UI, you have two options:
+
+1. Refer to the [docs](https://supertokens.com/docs/thirdpartyemailpassword/advanced-customizations/react-component-override/usage) on how to customize the pre-built UI.
+2. Roll your own UI by choosing "Custom UI" in the right sidebar in the [docs](https://supertokens.com/docs/thirdpartyemailpassword/quickstart/frontend-setup).
+
+## Additional resources
-- Follow the instructions on screen
+- Custom UI Example: https://github.com/supertokens/supertokens-web-js/tree/master/examples/react/with-thirdpartyemailpassword
+- Custom UI Blog post: https://supertokens.medium.com/adding-social-login-to-your-website-with-supertokens-custom-ui-only-5fa4d7ab6402
+- Awesome SuperTokens: https://github.com/kohasummons/awesome-supertokens
-## Author
+## Contributing
-Created with :heart: by the folks at supertokens.com.
+Please refer to the [CONTRIBUTING.md](https://github.com/supertokens/create-supertokens-app/blob/master/CONTRIBUTING.md) file in the root of the [`create-supertokens-app`](https://github.com/supertokens/create-supertokens-app) repo.
-## License
+## Contact us
-This project is licensed under the Apache 2.0 license.
+For any questions, or support requests, please email us at team@supertokens.io, or join our [Discord](https://supertokens.io/discord) server.
-## Notes
+## Authors
-- To know more about how this app works and to learn how to customise it based on your use cases refer to the [SuperTokens Documentation](https://supertokens.com/docs/guides)
-- We have provided development OAuth keys for the various built-in third party providers in the `/app/config/backend.ts` file. Feel free to use them for development purposes, but **please create your own keys for production use**.
+Created with :heart: by the folks at SuperTokens.io.
diff --git a/boilerplate/fullstack/remix/app/app.css b/boilerplate/fullstack/remix/app/app.css
index a1461c4e..d03d0e80 100644
--- a/boilerplate/fullstack/remix/app/app.css
+++ b/boilerplate/fullstack/remix/app/app.css
@@ -1,217 +1,179 @@
-html {
- height: 100%;
+/* Base styles */
+:root {
+ --primary-color: #ff9933;
+ --primary-hover: #ff8a15;
+ --success-color: #3eb655;
+ --success-bg: #e7ffed;
+ --border-color: #e0e0e0;
}
-.main {
+@font-face {
+ font-family: Menlo;
+ src: url("../assets/fonts/MenloRegular.ttf");
+}
+
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
+ "Droid Sans", "Helvetica Neue", sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+/* Layout */
+.app-container {
display: flex;
flex-direction: column;
- align-items: center;
- justify-content: center;
+ width: 100%;
min-height: 100vh;
+ font-family: Rubik, sans-serif;
}
-.appContainer {
- font-family: Rubik, sans-serif;
+.fill {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ flex: 1;
}
-.appContainer * {
- box-sizing: border-box;
+/* Header */
+header {
+ border-bottom: 2px solid var(--border-color);
+ padding: 8px;
}
-.bold400 {
- font-variation-settings: "wght" 400;
+header nav {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
}
-.bold500 {
- font-variation-settings: "wght" 500;
+header img {
+ width: 40px;
}
-.bold600 {
- font-variation-settings: "wght" 600;
+header ul {
+ display: flex;
+ gap: 12px;
+ list-style: none;
+ margin: 0;
+ padding: 0;
}
-.homeContainer {
- min-height: 100vh;
- min-width: 100vw;
- background: url("../assets/images/background.png");
- background-size: cover;
+header a {
+ color: var(--primary-color);
+ font-weight: 600;
+ text-decoration: none;
+}
+header a:hover {
+ color: var(--primary-hover);
+}
+
+/* Home page */
+#home-container {
+ align-items: center;
+ min-height: calc(100vh - 58px);
+ background: url("../assets/images/background.png") center/cover;
+}
+
+.logos {
display: flex;
- flex-direction: column;
- justify-content: center;
align-items: center;
+ gap: 20px;
+ padding-bottom: 80px;
}
-.bold700 {
- font-variation-settings: "wght" 700;
+.logos span {
+ font-size: 8rem;
+ font-weight: bold;
+}
+
+.logos img {
+ height: 240px;
+ width: auto;
}
-.mainContainer {
- box-shadow: 0px 0px 60px 0px rgba(0, 0, 0, 0.16);
+/* Main content */
+.main-container {
+ box-shadow: 0 0 60px rgba(0, 0, 0, 0.16);
width: min(635px, calc(100% - 24px));
border-radius: 16px;
- margin-block-end: 159px;
- background-color: #ffffff;
+ margin-bottom: 159px;
+ background-color: white;
}
-.successTitle {
- line-height: 1;
- padding-block: 26px;
- background-color: #e7ffed;
- text-align: center;
- color: #3eb655;
+.success-title {
display: flex;
justify-content: center;
- align-items: flex-end;
+ align-items: center;
+ padding: 26px;
+ background-color: var(--success-bg);
+ color: var(--success-color);
font-size: 20px;
+ line-height: 1;
}
-.successIcon {
+.success-title img {
margin-right: 8px;
}
-.innerContent {
- padding-block: 48px;
+.inner-content {
+ padding: 48px;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
}
-.userId {
+/* User ID display */
+#user-id {
position: relative;
- padding: 14px 17px;
- border-image-slice: 1;
width: min(430px, calc(100% - 30px));
- margin-inline: auto;
- margin-block: 11px 23px;
+ margin: 11px auto 23px;
+ padding: 14px 17px;
border-radius: 9px;
+ font-family: Menlo, monospace;
line-height: 1;
- font-family: Menlo, serif;
cursor: text;
+ border: 3px solid var(--primary-color);
}
-.userId:before {
- content: "";
- position: absolute;
- inset: 0;
- border-radius: 9px;
- padding: 2px;
- background: linear-gradient(90.31deg, #ff9933 0.11%, #ff3f33 99.82%);
- mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
- -webkit-mask-composite: xor;
- mask-composite: exclude;
-}
-
-.topBand,
-.bottomBand {
- border-radius: inherit;
-}
-
-.topBand {
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
-}
-
-.bottomBand {
- border-top-left-radius: 0;
- border-top-right-radius: 0;
+/* Buttons and navigation */
+.buttons {
+ display: flex;
+ gap: 4px;
}
-.sessionButton {
- padding-left: 13px;
- padding-right: 13px;
- padding-top: 8px;
- padding-bottom: 8px;
- cursor: pointer;
+.dashboard-button {
+ padding: 8px 13px;
+ background: var(--primary-color);
+ border: 1px solid var(--primary-hover);
+ border-radius: 6px;
+ box-shadow: 0 3px 6px rgba(255, 153, 51, 0.16);
color: white;
font-weight: bold;
- font-size: 17px;
-
- box-sizing: border-box;
- background: #ff9933;
- border: 1px solid #ff8a15;
- box-shadow: 0px 3px 6px rgba(255, 153, 51, 0.16);
- border-radius: 6px;
font-size: 16px;
-}
-
-.bottomCTAContainer {
- display: flex;
- justify-content: flex-end;
- padding-inline: 21px;
- background-color: #212d4f;
-}
-
-.viewCode {
- padding-block: 11px;
- color: #bac9f5;
- cursor: pointer;
- font-size: 14px;
-}
-
-.bottomLinksContainer {
- display: grid;
- grid-template-columns: repeat(4, auto);
- margin-bottom: 22px;
-}
-
-.linksContainerLink {
- display: flex;
- align-items: center;
- margin-inline-end: 68px;
cursor: pointer;
text-decoration: none;
- color: #000000;
-}
-
-.signOutLink {
- border: 0;
}
-.linksContainerLink:last-child {
- margin-right: 0;
+/* Footer */
+footer {
+ padding: 10px;
}
-.truncate {
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
+footer a {
+ color: var(--primary-color);
+ font-weight: 600;
+ /* text-decoration: none; */
}
-.separatorLine {
- max-width: 100%;
-}
-
-.linkIcon {
- width: 15px;
- margin-right: 5px;
-}
-
-@media screen and (max-width: 768px) {
- .bottomLinksContainer {
- grid-template-columns: repeat(2, 1fr);
- column-gap: 64px;
- row-gap: 34px;
- }
-
- .linksContainerLink {
- margin-inline-end: 0;
- }
-
- .separatorLine {
- max-width: 200px;
- }
-}
-
-@media screen and (max-width: 480px) {
- .homeContainer {
- justify-content: start;
- padding-block-start: 25px;
- }
-
- .mainContainer {
- margin-block-end: 90px;
- }
+footer a:hover {
+ color: var(--primary-hover);
}
diff --git a/boilerplate/fullstack/remix/app/config/appInfo.tsx b/boilerplate/fullstack/remix/app/config/appInfo.tsx
index 8f2a2479..80f09e99 100644
--- a/boilerplate/fullstack/remix/app/config/appInfo.tsx
+++ b/boilerplate/fullstack/remix/app/config/appInfo.tsx
@@ -1,6 +1,6 @@
export const appInfo = {
// learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
- appName: "SuperTokens Remix demo app",
+ appName: "SuperTokens + Remix",
apiDomain: "http://localhost:3000",
websiteDomain: "http://localhost:3000",
apiBasePath: "/supertokens",
diff --git a/boilerplate/fullstack/remix/app/config/frontend/all_auth.tsx b/boilerplate/fullstack/remix/app/config/frontend/all_auth.tsx
index 8643f6ab..1636d07d 100644
--- a/boilerplate/fullstack/remix/app/config/frontend/all_auth.tsx
+++ b/boilerplate/fullstack/remix/app/config/frontend/all_auth.tsx
@@ -27,6 +27,12 @@ export const frontendConfig = (): SuperTokensConfig => {
}),
Session.init(),
],
+ getRedirectionURL: async (context: any) => {
+ if (context.action === "SUCCESS") {
+ return "/dashboard";
+ }
+ return undefined;
+ },
};
};
diff --git a/boilerplate/fullstack/remix/app/config/frontend/emailpassword.tsx b/boilerplate/fullstack/remix/app/config/frontend/emailpassword.tsx
index f1ef3185..587422d9 100644
--- a/boilerplate/fullstack/remix/app/config/frontend/emailpassword.tsx
+++ b/boilerplate/fullstack/remix/app/config/frontend/emailpassword.tsx
@@ -8,6 +8,12 @@ export const frontendConfig = (): SuperTokensConfig => {
return {
appInfo,
recipeList: [EmailPasswordReact.init(), Session.init()],
+ getRedirectionURL: async (context: any) => {
+ if (context.action === "SUCCESS") {
+ return "/dashboard";
+ }
+ return undefined;
+ },
};
};
diff --git a/boilerplate/fullstack/remix/app/config/frontend/multifactorauth.tsx b/boilerplate/fullstack/remix/app/config/frontend/multifactorauth.tsx
index 51583bab..7da4d409 100644
--- a/boilerplate/fullstack/remix/app/config/frontend/multifactorauth.tsx
+++ b/boilerplate/fullstack/remix/app/config/frontend/multifactorauth.tsx
@@ -36,6 +36,12 @@ export const frontendConfig = (): SuperTokensConfig => {
TOTPReact.init(),
Session.init(),
],
+ getRedirectionURL: async (context: any) => {
+ if (context.action === "SUCCESS") {
+ return "/dashboard";
+ }
+ return undefined;
+ },
};
};
diff --git a/boilerplate/fullstack/remix/app/config/frontend/passwordless.tsx b/boilerplate/fullstack/remix/app/config/frontend/passwordless.tsx
index 9873152b..40fd9413 100644
--- a/boilerplate/fullstack/remix/app/config/frontend/passwordless.tsx
+++ b/boilerplate/fullstack/remix/app/config/frontend/passwordless.tsx
@@ -13,6 +13,12 @@ export const frontendConfig = (): SuperTokensConfig => {
}),
Session.init(),
],
+ getRedirectionURL: async (context: any) => {
+ if (context.action === "SUCCESS") {
+ return "/dashboard";
+ }
+ return undefined;
+ },
};
};
diff --git a/boilerplate/fullstack/remix/app/config/frontend/thirdparty.tsx b/boilerplate/fullstack/remix/app/config/frontend/thirdparty.tsx
index 2341e769..aa30fc4f 100644
--- a/boilerplate/fullstack/remix/app/config/frontend/thirdparty.tsx
+++ b/boilerplate/fullstack/remix/app/config/frontend/thirdparty.tsx
@@ -19,6 +19,12 @@ export const frontendConfig = (): SuperTokensConfig => {
}),
Session.init(),
],
+ getRedirectionURL: async (context: any) => {
+ if (context.action === "SUCCESS") {
+ return "/dashboard";
+ }
+ return undefined;
+ },
};
};
diff --git a/boilerplate/fullstack/remix/app/config/frontend/thirdpartyemailpassword.tsx b/boilerplate/fullstack/remix/app/config/frontend/thirdpartyemailpassword.tsx
index 791e9310..7a2c235a 100644
--- a/boilerplate/fullstack/remix/app/config/frontend/thirdpartyemailpassword.tsx
+++ b/boilerplate/fullstack/remix/app/config/frontend/thirdpartyemailpassword.tsx
@@ -22,6 +22,12 @@ export const frontendConfig = (): SuperTokensConfig => {
}),
Session.init(),
],
+ getRedirectionURL: async (context: any) => {
+ if (context.action === "SUCCESS") {
+ return "/dashboard";
+ }
+ return undefined;
+ },
};
};
diff --git a/boilerplate/fullstack/remix/app/config/frontend/thirdpartypasswordless.tsx b/boilerplate/fullstack/remix/app/config/frontend/thirdpartypasswordless.tsx
index 41e21b12..ea6e62bb 100644
--- a/boilerplate/fullstack/remix/app/config/frontend/thirdpartypasswordless.tsx
+++ b/boilerplate/fullstack/remix/app/config/frontend/thirdpartypasswordless.tsx
@@ -24,6 +24,12 @@ export const frontendConfig = (): SuperTokensConfig => {
}),
Session.init(),
],
+ getRedirectionURL: async (context: any) => {
+ if (context.action === "SUCCESS") {
+ return "/dashboard";
+ }
+ return undefined;
+ },
};
};
diff --git a/boilerplate/fullstack/remix/app/root.tsx b/boilerplate/fullstack/remix/app/root.tsx
index 44673a26..185abea6 100644
--- a/boilerplate/fullstack/remix/app/root.tsx
+++ b/boilerplate/fullstack/remix/app/root.tsx
@@ -1,4 +1,4 @@
-import { Meta, Links, Scripts, Outlet, ScrollRestoration, useLocation } from "@remix-run/react";
+import { Meta, Links, Scripts, Outlet, ScrollRestoration, useLocation, Link } from "@remix-run/react";
import SuperTokens, { SuperTokensWrapper } from "supertokens-auth-react";
import { frontendConfig } from "./config/frontend";
import { SessionAuth } from "supertokens-auth-react/recipe/session/index.js";
@@ -12,7 +12,7 @@ if (typeof window !== "undefined") {
export default function App() {
const location = useLocation();
- const isUnprotectedRoute = location.pathname.startsWith("/auth");
+ const isUnprotectedRoute = location.pathname.startsWith("/") || location.pathname.startsWith("/auth");
return (
@@ -20,18 +20,57 @@ export default function App() {
+ You're signed in already,
check out the Dashboard! 👇
+
Sign-in to continue
+ )}