Back to Supabase

Build a User Management App with SolidJS

apps/docs/content/guides/getting-started/tutorials/with-solidjs.mdx

1.26.085.3 KB
Original Source

<$Partial path="quickstart_intro.mdx" />

<Admonition type="note">

If you get stuck while working through this guide, you can find the full example on GitHub.

</Admonition>

<$Partial path="project_setup.mdx" variables={{ "framework": "solidjs", "tab": "frameworks" }} />

Building the app

Start building the SolidJS app from scratch.

Initialize a SolidJS app

You can use degit to initialize an app called supabase-solid:

bash
npx degit solidjs/templates/ts supabase-solid
cd supabase-solid

Then install the only additional dependency: supabase-js

bash
npm install @supabase/supabase-js

And finally save the environment variables in a .env with the API URL and the key that you copied earlier.

<$CodeTabs>

<$CodeSample path="/user-management/solid-user-management/.env.example" lines={[[1, -1]]} meta="name=.env" />

</$CodeTabs>

Now that you have the API credentials in place, create a helper file to initialize the Supabase client. These variables will be exposed on the browser, and that's completely fine since you have Row Level Security enabled on the Database.

<$CodeTabs>

<$CodeSample path="/user-management/solid-user-management/src/supabaseClient.tsx" lines={[[1, -1]]} meta="name=src/supabaseClient.tsx" />

</$CodeTabs>

App styling (optional)

An optional step is to update the CSS file src/index.css to make the app look better. You can find the full contents of this file in the example repository.

Set up a login component

Set up a SolidJS component to manage logins and sign ups using Magic Links, so users can sign in with their email without using passwords.

<$CodeTabs>

<$CodeSample path="/user-management/solid-user-management/src/Auth.tsx" lines={[[1, -1]]} meta="name=src/Auth.tsx" />

</$CodeTabs>

Account page

After a user is signed in allow them to edit their profile details and manage their account.

Create a new component for that called Account.tsx.

<$CodeTabs>

<$CodeSample path="/user-management/solid-user-management/src/Account.tsx" lines={[[1, 1], [3, 78], [87, -1]]} meta="name=src/Account.tsx" />

</$CodeTabs>

Profile photos

Next, add a way for users to upload a profile photo. Supabase configures every project with Storage for managing large files like photos and videos.

Create an upload widget

Start by creating a new component:

<$CodeTabs>

<$CodeSample path="/user-management/solid-user-management/src/Avatar.tsx" lines={[[1, -1]]} meta="name=src/Avatar.tsx" />

</$CodeTabs>

Update the Account component

With the Avatar component created, update src/Account.tsx to include it:

<$CodeTabs>

<$CodeSample path="/user-management/solid-user-management/src/Account.tsx" lines={[[1, -1]]} meta="name=src/Account.tsx" />

</$CodeTabs>

Launch!

With all the components in place, update App.tsx:

<$CodeTabs>

<$CodeSample path="/user-management/solid-user-management/src/App.tsx" lines={[[1, -1]]} meta="name=src/App.tsx" />

</$CodeTabs>

Once that's done, run this in a terminal window:

bash
npm start

And then open the browser to localhost:3000 and you should see the completed app.

At this stage you have a fully functional application!

Add a server route (SolidStart)

The example above is client-only. If you migrate the app to SolidStart for server-side rendering and API routes, you can add protected server endpoints with @supabase/server.

createSupabaseContext validates the incoming request's JWT locally (using your project's asymmetric signing keys, no round-trip to the Auth server), scopes a Supabase client to the authenticated user via RLS, and exposes the user's claims, all from a single call inside your SolidStart API route handler.

bash
npm install @supabase/server

<$CodeTabs>

typescript
import type { APIEvent } from '@solidjs/start/server'
import { createSupabaseContext } from '@supabase/server'

export async function GET({ request }: APIEvent) {
  const { data: ctx, error } = await createSupabaseContext(request, {
    auth: 'user',
  })

  if (error) {
    return Response.json({ message: error.message, code: error.code }, { status: error.status })
  }

  const { supabase, userClaims } = ctx
  const { data, error: queryError } = await supabase
    .from('profiles')
    .select('username, website, avatar_url')
    .eq('id', userClaims.id)
    .single()

  if (queryError) {
    return Response.json({ message: queryError.message }, { status: 500 })
  }

  return Response.json(data)
}

</$CodeTabs>

To make a route public, swap auth: 'user' for auth: 'none'. For app-wide authentication via SolidStart middleware, or for the full @supabase/server API, see the getting started guide.