SDK Integrations

Add Passji to your app using your favorite auth library. We're a standard OIDC provider, so any OAuth 2.0 / OpenID Connect library works.

Supported Libraries

Passji works with any OIDC-compliant auth library. Here are guides for the most popular options:

Environment Variables

All integrations require your Passji credentials. Get these from the Developer Portal.

.env
# .env
PASSJI_CLIENT_ID=your_client_id
PASSJI_CLIENT_SECRET=your_client_secret

Auth.js (NextAuth)
Recommended

Auth.js (formerly NextAuth.js) is the most popular authentication library for Next.js applications. It has built-in support for OIDC providers.

auth.ts
// auth.ts (Auth.js v5 / NextAuth)
import NextAuth from "next-auth"

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [
    {
      id: "passji",
      name: "Passji",
      type: "oidc",
      issuer: "https://passji.com",
      clientId: process.env.PASSJI_CLIENT_ID,
      clientSecret: process.env.PASSJI_CLIENT_SECRET,
      authorization: {
        params: { scope: "openid emoji trust" }
      },
      profile(profile) {
        return {
          id: profile.sub,
          emojiId: profile.emoji_id,
          trustScore: profile.trust_score,
        }
      },
    },
  ],
})

Coming Soon: We're building an official @passji/authjs provider with full TypeScript types for emoji claims and trust scores.

Better Auth
Recommended

Better Auth is a modern authentication library with excellent TypeScript support and a clean API.

auth.ts
// auth.ts (Better Auth)
import { betterAuth } from "better-auth"

export const auth = betterAuth({
  socialProviders: {
    passji: {
      clientId: process.env.PASSJI_CLIENT_ID!,
      clientSecret: process.env.PASSJI_CLIENT_SECRET!,
      issuer: "https://passji.com",
      scopes: ["openid", "emoji", "trust"],
      // Map claims to user profile
      mapProfileToUser: (profile) => ({
        id: profile.sub,
        name: profile.emoji_id,
        image: null, // Passji has no profile images
        trustScore: profile.trust_score,
      }),
    },
  },
})

Passport.js
Supported

Passport.js is the classic authentication middleware for Node.js/Express applications. Use the passport-openidconnect strategy.

passport.js
// passport.js (Passport.js with OpenID Connect)
import passport from "passport"
import { Strategy as OIDCStrategy } from "passport-openidconnect"

passport.use("passji", new OIDCStrategy({
    issuer: "https://passji.com",
    authorizationURL: "https://passji.com/authorize",
    tokenURL: "https://passji.com/token",
    userInfoURL: "https://passji.com/userinfo",
    clientID: process.env.PASSJI_CLIENT_ID,
    clientSecret: process.env.PASSJI_CLIENT_SECRET,
    callbackURL: "https://yourapp.com/auth/passji/callback",
    scope: ["openid", "emoji", "trust"],
  },
  (issuer, profile, done) => {
    // profile contains the claims from userinfo
    return done(null, {
      id: profile.id,
      emojiId: profile._json.emoji_id,
      trustScore: profile._json.trust_score,
    })
  }
))

Lucia Auth
Supported

Lucia is a lightweight session management library. Use Arctic (same author) for the OAuth flow.

auth.ts
// auth.ts (Lucia Auth with Arctic)
import { Lucia } from "lucia"
import { Arctic } from "arctic"

// Arctic supports generic OIDC
const passji = new Arctic.OIDC(
  "https://passji.com",
  process.env.PASSJI_CLIENT_ID!,
  process.env.PASSJI_CLIENT_SECRET!,
  "https://yourapp.com/auth/passji/callback"
)

// Create authorization URL
export function createPassjiAuthURL(state: string, codeVerifier: string) {
  return passji.createAuthorizationURL(state, codeVerifier, {
    scopes: ["openid", "emoji", "trust"]
  })
}

// Exchange code for tokens
export async function validateCallback(code: string, codeVerifier: string) {
  const tokens = await passji.validateAuthorizationCode(code, codeVerifier)
  // Decode the id_token or call userinfo
  return tokens
}

Generic OIDC Client
Universal

Using a library not listed here? Any standard OIDC client will work. Here's an example with openid-client:

auth.ts
// Generic OIDC client (openid-client)
import { Issuer } from "openid-client"

const passjiIssuer = await Issuer.discover("https://passji.com")

const client = new passjiIssuer.Client({
  client_id: process.env.PASSJI_CLIENT_ID,
  client_secret: process.env.PASSJI_CLIENT_SECRET,
  redirect_uris: ["https://yourapp.com/callback"],
  response_types: ["code"],
})

// Generate authorization URL
const authUrl = client.authorizationUrl({
  scope: "openid emoji trust",
  state: crypto.randomUUID(),
  code_challenge: codeChallenge,
  code_challenge_method: "S256",
})

// Exchange code for tokens
const tokenSet = await client.callback(
  "https://yourapp.com/callback",
  { code, state },
  { code_verifier: codeVerifier }
)

// Get user info
const userinfo = await client.userinfo(tokenSet.access_token)

Integration Tips

  • Always use PKCE for single-page apps (SPAs) and mobile apps
  • Request the trust scope to get trust scores - useful for progressive access control
  • The emoji_id claim can be displayed directly - it's a user-friendly identifier
  • Store the sub claim as the unique user ID - emoji sequences could theoretically change
  • Handle token refresh - access tokens expire after 1 hour, use the refresh token to get new ones