Socket
Socket
Sign inDemoInstall

elysoid

Package Overview
Dependencies
29
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    elysoid

Minimal, fully typesafe OpenID Elysia plugin for single page apps with stateless session management with JWT.


Version published
Weekly downloads
4
Maintainers
1
Install size
6.19 MB
Created
Weekly downloads
 

Readme

Source

Elysoid

Minimal, fully typesafe OpenID Elysia plugin for single page apps with stateless session management with JWT.

Basic setup

bun add elysoid
// plugin/auth.ts
import { Static, t } from "elysia"
import { IdTokenPayload, auth as authPlugin } from "elysoid"

const SessionSchema = t.Object({
  id: t.String(),
  roles: t.Array(t.String())
}) // create any session schema that you need for your app
type Session = Static<typeof SessionSchema>

// type IdTokenPayload = { sub: string, email?: string, name?: string }
const login = async (payload: IdTokenPayload): Promise<Session | null> => {
  
  // Get user from DB, based on "sub" (or create)
  // - with all required data for session
  // - return null if not authorized to login

  return {
    id: "1",
    roles: [ "admin" ]
  }
}

export const auth = authPlugin(SessionSchema, login)
// index.ts
import { Elysia, t } from "elysia"
import { AuthenticationError, AuthorizationError } from "elysoid"
import { auth } from "./plugin/auth"

const app = new Elysia()
  .use(auth)  // /social-login endpoint registered - see eden treaty below
  .post("/api/demo", ({ body, user }) => { // user is typed as Session | null
    if (!user)
      throw new AuthenticationError()       // handled, will return 401
    if (!user.roles.includes("admin"))
      throw new AuthorizationError()        // handled, will return 403
    return { msg: `${body.data} received from ${user.id}` }
  },
  {
    body: t.Object({ data: t.String() }),
    response: t.Object({ msg: t.String() })
  })
  .listen(3000)

console.log(
  `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`
)

export type App = typeof app
# .env (or environment variables)
TOKEN_ENDPOINT=https://openidprovider.com/token
CLIENT_ID=yourlientid
CLIENT_SECRET=yourclientsecret
REDIRECT_URI=https://yourapp.com/callback

JWT_SECRET=shhhh
JWT_EXP=2h

LOG_LEVEL=trace
# and / or
AUTH_LOG_LEVEL=trace    # takes precedence
# default log level is off - no logs from auth plugin
# [ "fatal", "error", "warn", "info", "debug", "trace", "all" ]
// on the client
import { edenTreaty } from '@elysiajs/eden'
import type { App } from '../../api/src/index'

const app = edenTreaty<App>('http://localhost:3000')

const login = async () => {
  // get code from url (query param)
  const response = await app['social-login'].post({
    code: "<from query param>"
  })
  // type Response = { sessionToken: string }
  // save sessionToken
  // and then send it on all subsequent request
  // in "authorization" header
}

And that's it.

Advanced setup

You might want to connect to multiple providers, or configure certain other aspects of the plugin. With the typed config it is pretty self-explanatory, here is a full example nonetheless.

// plugin/auth.ts
import { Static, t } from "elysia"
import { IdTokenPayload, multiProviderAuth as authPlugin } from "elysoid"

const SessionSchema = t.Object({
  id: t.String(),
  roles: t.Array(t.String())
}) // create any session schema that you need for your app
type Session = Static<typeof SessionSchema>

// type IdTokenPayload = { sub: string, email?: string, name?: string }
const login = async (payload: IdTokenPayload, provider: string): Promise<Session | null> => {
  
  // Get user from DB, based on "sub" (or create)
  // - BASED ON PROVIDER!!! ("google", "apple"... see below in the config)
  // - with all required data for session
  // - return null if not authorized to login

  return {
    id: "1",
    roles: [ "admin" ]
  }
}

export const auth = authPlugin(SessionSchema, login, {
  session: {
    authHeader: "authorization",
    tokenPrefix: "Bearer ",
  },
  jwt: {
    secret: "shhh",
    expiration: "2h",
  },
  providers: {
    'google': {
      tokenEndpoint: "https://google.com/token",
      clientId: "yourgoogleclientid",
      clientSecret: "yourgoogleclientsecret",
      redirectUri: "https://yourapp.com/googlecb"
    },
    'apple': {
      tokenEndpoint: "https://apple.com/token",
      clientId: "yourappleclientid",
      clientSecret: "yourappleclientsecret",
      redirectUri: "https://yourapp.com/applecb"
    },
  }
}, (logMessage) => console.log(logMessage)) 
// on the client
import { edenTreaty } from '@elysiajs/eden'
import type { App } from '../../api/src/index'

const app = edenTreaty<App>('http://localhost:3000')

const login = async () => {
  // get code from url (query param)
  const response = await app['social-login'].post({
    code: "<from query param>",
    provider: "google"  // based on where were you redirected to
  })
  // type Response = { sessionToken: string }
  // save sessionToken
  // and then send it on all subsequent request
  // in "authorization" header
}

Keywords

FAQs

Last updated on 05 Dec 2023

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc