npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@zentered/auth0-solid-start

v1.7.0

Published

Auth0 for Solid-Start

Downloads

53

Readme

Auth0 Solid Start (SSR compatible)

Publish

This is a fully functional library to add Auth0 OAuth Authentication to a Solid-Start App.

You'll need to sign up and create an Auth0 Application to use this library. The credentials are stored in an .env file (see .env.example).

This work is inspired by

How it works

This library is intended to be used on root level of your Solid-Start App. It provides an authentication context for the entire App. Users/passwords etc. are all stored in Auth0, we use the Universal Login Experience to authenticate users and get a code, which we can exchange for an access_token. The access_token is a valid JWT token and can be used to authenticate requests to your API / GraphQL /etc.

The callback URL is set to /auth/callback, so you need to create an API route in src/routes/auth/callback.js/ts. The code can be found below.

flowchart
    A[Browser] --> B[Initial Render/SSR]
    B{Valid Session Cookie exists?} --> |Yes| C
    C[Set Signals & Render App]
    B --> |No| D[Redirect to Auth0 Universal Login]
    D --> E[Callback to `/auth/callback` with `code` & `state`]
    E --> F[Exchange `code` for `access_token`]
    F --> G[Get User Info with access_token]
    G --> H[Set Signals & Session Cookie]
    H --> C[Render App]

Multi Tenant Mode

Multi Tenant Mode can be used with Auth0 Organizations. You'll have to pass an organization object into the Auth0 context with an id. We recommend using the same schema as Auth0.

Set VITE_AUTH0_REWRITE_REDIRECT=true in .env

Usage

Environment Variables

See .env.example

  • VITE_AUTH0_REWRITE_REDIRECT requires the Auth0 Organization setup
  • VITE_AUTH0_OFFLINE_ACCESS requires the Auth0 API to be configured with offline access
  • VITE_AUTH0_LOGOUT_URL the logout url (a server-side route, ie http://localhost:8080/auth/logout)

vite.config.ts/js

There's an issue with vite throwing process is undefined errors when the session is loaded on the client. To fix this, add the following to your vite.config.ts/js:

define: {
    'process.env': process.env
  },

root.jsx / .tsx

In root.tsx to enforce authentication on all pages:

import { Show, Suspense } from 'solid-js'
import { isServer } from 'solid-js/web'
import { ErrorBoundary, FileRoutes, Routes } from 'solid-start'
import { Auth0, useAuth0 } from '@zentered/auth0-solid-start'

const GraphQLProvider = () => {} // let's assume you want to authenticate graphql requests with your JWT

function Login(props) {
  return (
    <div>
      <p>Sign in</p>
      <div>
        <div>
          <a onClick={() => props.auth0.authorize()} type="button">
            Log In
          </a>
        </div>
      </div>
    </div>
  )
}

function SiteRequiresAuth(props) {
  const auth0 = useAuth0()

  if (!auth0.isAuthenticated() && !isServer) {
    auth0.login()
  }

  return (
    <>
      <Show when={auth0.isInitialized()}>
        <Show when={auth0.isAuthenticated()} fallback={<Login auth0={auth0} />}>
          <Show when={auth0.accessToken()}>
            <GraphQLProvider auth0={auth0}>{props.children}</GraphQLProvider>
          </Show>
        </Show>
      </Show>
    </>
  )
}

export default function Root() {
  return (
    // ...
    <Suspense>
      <ErrorBoundary>
        <Auth0
          domain={import.meta.env.VITE_AUTH0_DOMAIN}
          clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
          audience={import.meta.env.VITE_AUTH0_AUDIENCE}
          redirectUri={import.meta.env.VITE_AUTH0_REDIRECT_URI}
          logoutUrl={`${import.meta.env.VITE_BASE_URL}/auth/logout`}
          // organization={organization} // uncomment if you use auth0 organizations
        >
          <SiteRequiresAuth>
            <Routes>
              <FileRoutes />
            </Routes>
          </SiteRequiresAuth>
        </Auth0>
      </ErrorBoundary>
    </Suspense>
    // ...
  )
}

With Organization Invitation

If you use Auth0 Organizations, you can pass through the invitation, organization and organization_name query params to the Auth0 Universal Login Experience. This will load the sign-up instead of the login form:

// root.jsx/tsx
const [searchParams] = useSearchParams()

if (searchParams.invitation) {
  auth0.setInvitation(
    searchParams.invitation,
    searchParams.organization,
    searchParams.organization_name
  )
}

Logout

The logout happens in 3 steps:

  1. User clicks "Sign out" and starts the process
  2. logout function on the Auth0 Provider is triggered that generates an auth0 logout url
  3. Auth0 redirects back to the "logout url" which clears the session.

There are two parts: the logout function in the auth0 provider and the "api" route (ie /auth/logout), see below.

In any component/page where you want the "Sign out" link:

import { useAuth0 } from '@zentered/auth0-solid-start'
import { Link } from '@solidjs/router'

export default function Component() {
  const auth0 = useAuth0()
  const [, logout] = createRouteAction(async () => {
    await auth0.logout()
  })

  <Link
    href="#"
    class={`button`}
    onClick={() => logout()}
  >
    Sign Out
  </Link>
}

API

Callback

routes/auth/callback.js|ts:

import fn from '@zentered/auth0-solid-start/api/callback'

export async function GET({ request }) {
  return fn(request)
}

Logout API

routes/auth/logout.js|ts:

import fn from '@zentered/auth0-solid-start/api/logout'

export function GET({ request }) {
  return fn(request)
}

Development

You can fork/clone this repository and link it into your working project with pnpm link:

cd auth0-solid-start
pnpm link

cd ../your-project
pnpm link @zentered/auth0-solid-start ../../auth0-solid-start

Instead of using the npm version you're now working with a local copy. Changes in the auth0-solid-start folder should restart the app.