CloudNativeEntrepreneur / sveltekit-web3auth

Web3 auth via JWTs for Sveltekit
MIT License
29 stars 3 forks source link

sveltekit + web3auth

This project aims to integrate web3auth via MetaMask with a JWT Issuing auth server from a confidential client for use with APIs in Sveltekit. Once login is complete, Navigation to protected pages of app don't require a request to Authorization Server. Sveltekit hooks take care of :

[x] Silent Refresh Workflow
[x] Validating the client accessToken validity
[x] Renewing the token in case of token expiry
[x] Offline Auth server error handling
[x] Setting valid user information ( accessToken, refreshToken, userid etc. ) in form of cookies
[x] Populating session variable with user information

When the client side kicks in, it:

[x] Checks for user and Auth server information in session variable
[x] In case, no user is found or some error has occured on server-side, populate AuthStore with proper messages
[x] Provides Login, Logout functionality
[x] Initiates authorization flow, in case of protected component via Sveletkit Load method.
[x] Logout in one browser tab initiates automatic logout from all tabs.
[x] Prompt on all browser tabs and Page reloading on User Login.

Goal is complete JWT Implementation based on Hasura Blog on BEST Practices for JWT AUTH in context of meta mask login and challenge/signature auth flow.

More useful reading:

Npm Package link

https://www.npmjs.com/package/sveltekit-web3auth

Usage

Template

The easiest way to get started is with the template: https://github.com/CloudNativeEntrepreneur/sveltekit-web3auth-template

Installation

npm i sveltekit-web3auth --save-dev

Server

You can use this server: CloudNativeEntrepreneur/web3-auth-service

Configuration

Create an .env file in project root with following content

VITE_WEB3_AUTH_ISSUER="http://localhost:8000"
VITE_WEB3_AUTH_CLIENT_ID="local-public"
VITE_WEB3_AUTH_CLIENT_SECRET="1439e34f-343e-4f71-bbc7-cc602dced84a"
// VITE_WEB3_AUTH_POST_LOGOUT_REDIRECT_URI="http://localhost:3000" // optional, just set to enable
VITE_WEB3_AUTH_TOKEN_REFRESH_MAX_RETRIES="5"
VITE_GRAPHQL_URL=http://hasura.default.127.0.0.1.sslip.io/v1/graphql
VITE_GRAPHQL_INTERNAL_URL=http://hasura.default.127.0.0.1.sslip.io/v1/graphql
VITE_GRAPHQL_WS_URL=ws://hasura.default.127.0.0.1.sslip.io/v1/graphql

Inside your src/global.d.ts

interface ImportMetaEnv {
  VITE_WEB3AUTH_ISSUER: string;
  VITE_WEB3AUTH_CLIENT_ID: string;
  VITE_WEB3AUTH_CLIENT_SECRET: string;
  VITE_WEB3AUTH_POST_LOGOUT_REDIRECT_URI?: string;
  VITE_WEB3AUTH_TOKEN_REFRESH_MAX_RETRIES: number;
  VITE_GRAPHQL_URL: string;
  VITE_GRAPHQL_INTERNAL_URL: string;
  VITE_GRAPHQL_WS_URL: string;
}

Auth Endpoints

SvelteKit only includes the $lib folder in published packages, so you'll need to set up the needed routes to support the confidential authentication flow in your own project.

From the source repo of sveltekit-web3auth, copy the src/routes/auth folder into your own SvelteKit project. Also copy the src/config folder, the src/hooks.ts file, and src/routes/__layout.svelte into the same spots in your own project.

Replace imports of $lib with sveltekit-web3auth.

You may also optionally copy in the routes/graphql and routes/profile

Feel free to customize them after this point.

Use these stores for auth information

<script lang="ts">
  import {
    isAuthenticated,
    isLoading,
    authError,
    accessToken,
    idToken,
    userInfo,
    refreshToken,
    LoginButton,
  } from "sveltekit-web3auth";
</script>

{#if $isAuthenticated}
<div>User is authenticated</div>
{:else}
<LoginButton class="btn btn-primary">Login</LoginButton>
{/if}
<div></div>

For protected routes

<script lang="ts">
  import { ProtectedRoute, LogoutButton } from "sveltekit-web3auth";
</script>

<ProtectedRoute>
  <div
    class="h-screen-minus-navbar bg-gray-800 text-white flex flex-col justify-center items-center w-full"
  >
    This is a protected page

    <LogoutButton class="btn btn-primary">Logout</LogoutButton>
  </div>
</ProtectedRoute>

Application Screenshots

Login / Index page

Login Page

Once user clicks login, Redirection to Auth server

Metamask Auth

Auth Complete - client hydrated with accessToken

Index page with JWT

Protected Page and Session variables with user info

Index page with JWT

Developing

Once you've created a project and installed dependencies with npm ci, start a development server:

npm run dev

Building

When building for production, sveltekit will use .env.production values.

In production mode it's important to build with a blank VITE_WEB3AUTH_CLIENT_SECRET so it is not accessible on the client side. Instead, WEB3AUTH_CLIENT_SECRET will be accessible to the process at runtime during a run of a production build.

npm run build

FAQ

YOUR SECRET IS EXPOSED

Yes, I know.

It'll only work in the local development cluster - this is part of an example that contains several moving parts, so I just generated some random secrets where they were needed and preconfigured things accordingly so you can just run it locally and everything will work. Couldn't go without secrets as part of that example is an authentication server and it's JWT integration with Hasura.

Don't use these proconfigured values in production. I typically use ExternalSecrets in prod.

Additionally, because Sveltekit generates code for the client and server (at least in this example), we need to be careful about how to build and configure prod, and I wanted to provide an example of that too.

I generally deploy things to Kubernetes, which is what the charts folder is for, and in a real chart I'd use ExternalSecrets to provide those values.