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

@tripleslate/provenance

v0.11.0

Published

server-side SvelteKit auth

Downloads

451

Readme

provenance

npm version license

Server-side OAuth/OIDC implementation for SvelteKit

features

  • Create a handle for programmatically defining auth functionality in server hooks
    • handle requests to redirectUri, login, and logout routes
    • refresh access tokens (if refresh tokens used by the provider)
    • add a session object to event.locals
    • track the referrer for redirect after login
  • Provide a protectRoute function for redirecting user without session to login
  • Expose a callback to include extra information in the stored cookie session given tokens data

installation

npm i --save-dev @tripleslate/provenance

usage

See the example project to see the following writeup in action.

include vite plugin

Include provenance in the vite plugin pipeline. It will generate a light "runtime" that forms the bridge between your project's version of sveltekit and the provenance core logic.

vite.config.ts

import { defineConfig } from 'vite';

import { sveltekit } from '@sveltejs/kit/vite';
import { provenance } from '@tripleslate/provenance/vite';

export default defineConfig({
  // provenance first
  plugins: [provenance(), sveltekit()]
});

src/lib/server/PROVENANCE.ts will be written on vite dev server start and build and should be checked in. This output file location can be customized and optionally output in js.

create auth object

src/lib/server/auth.ts

github
import { provenance } from './PROVENANCE';
import { github } from '@tripleslate/provenance/providers';
import { GH_CLIENT_ID, GH_CLIENT_SECRET } from '$env/static/private';

export const auth = provenance(github({ clientId: GH_CLIENT_ID, clientSecret: GH_CLIENT_SECRET }));
keycloak
import { provenance } from './PROVENANCE';
import { keycloak } from '@tripleslate/provenance/providers';
import { KC_BASE, KC_REALM, KC_CLIENT_ID, KC_CLIENT_SECRET } from '$env/static/private';

export const auth = provenance(
  keycloak({
    base: KC_BASE,
    realm: KC_REALM,
    clientId: KC_CLIENT_ID,
    clientSecret: KC_CLIENT_SECRET
  })
);

match the App interfaces to your provider and session callback

You will not be able to access session data from locals if your App.Session interface does not match the provider and sessionCallback passed to $provenance.provenance (see "create auth object").

src/app.d.ts

declare global {
  namespace App {
    interface Session {
      accessToken: string;
    }

    // interface Error {}
    // interface Locals {}
    // interface PageData {}
    // interface Platform {}
  }
}

export {};

Above example applies to github provider. Refer to the fields in the Session generic parameter on other providers. Note that Locals does not need to be defined, provenance provides a default session field of type (App.Session & App.SessionExtra) | null. If an app defines other Locals fields, they can be defined here without redefining session on Locals as typescript will merge the two declarations of the interface.

intialize handle hook

src/hooks.server.ts

import { auth } from '$lib/server/auth';

export const handle = auth.handle;

protect a route

src/routes/protected/+page.server.ts

import { auth } from '$lib/server/auth';

export const load = async (event) => {
  const session = await auth.protectRoute(event);

  return {
    session
  };
};

Note that handle in hooks.server.ts is not invoked during client side routing (typically, navigating to a page without a +page.server.ts after first load). This means that protecting a route with auth.protectRoute and accessing (up to date) session information must be done in a +page.server.ts load, not a +page.ts load.

add extra information to session

src/app.d.ts

Extend the App.SessionExtra interface (provenance defines this interface as an empty object by default). Note that this example extends the App.SessionExtra type with an App.User field.

declare global {
  namespace App {
    interface User {
      displayName: string;
    }
    interface Session {
      accessToken: string;
      idToken: string;
      user: User;
    }
    ...
  }
}

export {};

src/lib/server/auth.ts

Include a session callback in the auth definition to decode the idToken JWT into some user information (available data depends on your provider/creativity).

import { parseJWT } from '@oslojs/jwt';

import { provenance } from './PROVENANCE';
import { keycloak } from '@tripleslate/provenance/providers';
import { KC_BASE, KC_REALM, KC_CLIENT_ID, KC_CLIENT_SECRET } from '$env/static/private';

export const auth = provenance(
  keycloak({
    base: KC_BASE,
    realm: KC_REALM,
    clientId: KC_CLIENT_ID,
    clientSecret: KC_CLIENT_SECRET,
    scopes: ['openid', 'profile', 'email']
  }),
  {
    sessionCallback: (session) => {
      const idToken = parseJWT(session.idToken)[1] as { name: string };

      return {
        ...session,
        user: {
          displayName: idToken.name
        }
      };
    }
  }
);

src/routes/protected/+page.server.ts

Access the user field on the session object.

import { auth } from '$lib/server/auth';

export const load = async (event) => {
  const { user } = await auth.protectRoute(event);

  return {
    user
  };
};