Yuki UIYuki UI

Installation

Follow these steps to install Auth in your project. The installation process may vary slightly depending on your framework and database choice.

Getting Started

CLI

  1. Install Auth Package
npx shadcn@latest add https://yuki-ui.vercel.app/r/auth.json
npx shadcn@latest add https://yuki-ui.vercel.app/r/auth.json
pnpm dlx shadcn@latest add https://yuki-ui.vercel.app/r/auth.json
bunx --bun shadcn@latest add https://yuki-ui.vercel.app/r/auth.json

By default, Auth uses Scrypt for hashing passwords. You can change the hashing algorithm by passing a different hashing function to the hash and verify methods in the server/auth/core/password.ts.

  1. Add Adapter (Optional)

Frist, create your database schema to store authentication data.

Install necessary packages.

npm install -d drizzle-kit
pnpm add -d drizzle-kit
yarn add -d drizzle-kit
bun add -d drizzle-kit
npm install drizzle-orm
pnpm add drizzle-orm
yarn add drizzle-orm
bun add drizzle-orm

Create a new table in your database.

server/db/schema.ts
import { relations } from 'drizzle-orm'
import { pgTable, primaryKey } from 'drizzle-orm/pg-core'

export const users = pgTable('user', (t) => ({
  id: t.uuid().primaryKey().defaultRandom().notNull(),
  name: t.varchar({ length: 255 }).notNull(),
  email: t.varchar({ length: 255 }).unique().notNull(),
  image: t.varchar({ length: 255 }).notNull(),
  createdAt: t.timestamp().defaultNow().notNull(),
  updatedAt: t
    .timestamp({ mode: 'date', withTimezone: true })
    .defaultNow()
    .$onUpdateFn(() => new Date())
    .notNull(),
}))

export const usersRelations = relations(users, ({ many }) => ({
  accounts: many(accounts),
  sessions: many(sessions),
}))

export const accounts = pgTable(
  'account',
  (t) => ({
    provider: t.varchar({ length: 255 }).notNull(),
    accountId: t.varchar({ length: 255 }).notNull(),
    userId: t
      .uuid()
      .notNull()
      .references(() => users.id, { onDelete: 'cascade' }),
    password: t.varchar({ length: 255 }),
  }),
  (account) => [primaryKey({ columns: [account.provider, account.accountId] })],
)

export const accountsRelations = relations(accounts, ({ one }) => ({
  user: one(users, { fields: [accounts.userId], references: [users.id] }),
}))

export const sessions = pgTable('session', (t) => ({
  token: t.varchar({ length: 255 }).primaryKey().notNull(),
  expires: t.timestamp({ mode: 'date', withTimezone: true }).notNull(),
  userId: t
    .uuid()
    .notNull()
    .references(() => users.id, { onDelete: 'cascade' }),
}))

export const sessionRelations = relations(sessions, ({ one }) => ({
  user: one(users, { fields: [sessions.userId], references: [users.id] }),
}))

Export your database instance.

server/db/index.ts
import { drizzle } from 'drizzle-orm/node-postgres'

import * as schema from '@/server/db/schema'

const createDrizzleClient = () =>
  drizzle(process.env.DATABASE_URL, {
    schema,
    casing: 'snake_case',
  })
const globalForDrizzle = globalThis as unknown as {
  db: ReturnType<typeof createDrizzleClient> | undefined
}
export const db = globalForDrizzle.db ?? createDrizzleClient()
if (process.env.NODE_ENV !== 'production') globalForDrizzle.db = db

Install necessary packages.

npm install -d prisma
pnpm add -d prisma
yarn add -d prisma
bun add -d prisma
npm install @prisma/client
pnpm add @prisma/client
yarn add @prisma/client
bun add @prisma/client

Create a new table in your database.

prisma/schema.prisma
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"

  moduleFormat        = "esm"
  importFileExtension = ""
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        String   @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
  name      String   @db.VarChar(255)
  email     String   @unique(map: "user_email_unique") @db.VarChar(255)
  image     String   @db.VarChar(255)
  createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6)
  updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(6)

  accounts Account[]
  sessions Session[]

  @@map("user")
}

model Account {
  provider  String  @db.VarChar(255)
  accountId String  @map("account_id") @db.VarChar(255)
  password  String? @db.VarChar(255)

  userId String @map("user_id") @db.Uuid
  user   User   @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "account_user_id_user_id_fk")

  @@id([provider, accountId], map: "account_provider_account_id_pk")
  @@map("account")
}

model Session {
  token   String   @id @db.VarChar(255)
  expires DateTime @db.Timestamptz(6)

  userId String @map("user_id") @db.Uuid
  user   User   @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "session_user_id_user_id_fk")

  @@map("session")
}

Export your database instance.

server/db.ts
import { PrismaClient } from '@/generated/prisma'

const createPrismaClient = () => new PrismaClient()
const globalForPrisma = globalThis as unknown as {
  db: ReturnType<typeof createPrismaClient> | undefined
}
export const db = globalForPrisma.db ?? createPrismaClient()
if (process.env.NODE_ENV !== 'production') globalForPrisma.db = db

Install necessary packages.

npm install mongoose
pnpm add mongoose
yarn add mongoose
bun add mongoose

Create a new table in your database.

server/db/schema.ts
import type { Document, Model } from 'mongoose'
import { model, models, Schema, Types } from 'mongoose'

export interface User extends Document {
  name: string
  email: string
  image: string
  createdAt: Date
  updatedAt: Date
}

const userSchema = new Schema(
  {
    name: { type: String, required: true },
    email: { type: String, required: true, unique: true },
    image: { type: String, required: true },
  },
  { timestamps: { createdAt: true, updatedAt: true } },
)

export const user: Model<User> = models.user ?? model<User>('user', userSchema)

export interface Account extends Document {
  provider: string
  accountId: string
  password?: string
  userId: string
}

const accountSchema = new Schema(
  {
    provider: { type: String, required: true },
    accountId: { type: String, required: true },
    password: { type: String, required: false },
    userId: { type: Types.ObjectId, required: true, ref: 'user' },
  },
  { timestamps: false },
)

accountSchema.index({ provider: 1, accountId: 1 }, { unique: true })

export const account: Model<Account> =
  models.account ?? model<Account>('account', accountSchema)

export interface Session extends Document {
  token: string
  expires: Date
  userId: string
}

const sessionSchema = new Schema(
  {
    token: { type: String, required: true, unique: true },
    expires: { type: Date, required: true },
    userId: { type: Types.ObjectId, required: true, ref: 'user' },
  },
  { timestamps: false },
)

export const session: Model<Session> =
  models.session ?? model<Session>('session', sessionSchema)

Export your database instance.

server/db/index.ts
import mongoose from 'mongoose'

import * as schema from '@/server/db/schema'

const createMongooseClient = () => {
  void mongoose.connect(process.env.DATABASE_URL ?? '')
  return schema
}
const globalForMongoose = globalThis as unknown as {
  db: ReturnType<typeof createMongooseClient> | undefined
}
export const db = globalForMongoose.db ?? createMongooseClient()
if (process.env.NODE_ENV !== 'production') globalForMongoose.db = db

Then, run this command to install adapter

npx shadcn@latest add https://yuki-ui.vercel.app/r/auth-with-{database}.json
npx shadcn@latest add https://yuki-ui.vercel.app/r/auth-with-{database}.json
pnpm dlx shadcn@latest add https://yuki-ui.vercel.app/r/auth-with-{database}.json
bunx --bun shadcn@latest add https://yuki-ui.vercel.app/r/auth-with-{database}.json

Replace {database} with your database adapter. Currently supported databases:

  • drizzle
  • prisma
  • mongodb
  • memory
  1. Install OAuth providers.

These OAuth providers are implemented using Arctic, a collection of OAuth 2.0 clients for popular providers.

npx shadcn@latest add https://yuki-ui.vercel.app/r/oauth-{provider}.json
npx shadcn@latest add https://yuki-ui.vercel.app/r/oauth-{provider}.json
pnpm dlx shadcn@latest add https://yuki-ui.vercel.app/r/oauth-{provider}.json
bunx --bun shadcn@latest add https://yuki-ui.vercel.app/r/oauth-{provider}.json

Replace {provider} with the OAuth provider you want to use. Currently supported providers:

  • discord
  • facebook
  • figma
  • github
  • google
  • microsoft (not recommended, it returns image blob instead of image url)
  • notion
  • spotify

Example:

npx shadcn@latest add https://yuki-ui.vercel.app/r/oauth-google.json
npx shadcn@latest add https://yuki-ui.vercel.app/r/oauth-google.json
pnpm dlx shadcn@latest add https://yuki-ui.vercel.app/r/oauth-google.json
bunx --bun shadcn@latest add https://yuki-ui.vercel.app/r/oauth-google.json

Remember to add environment variables for your OAuth providers. You can find the required environment variables in the documentation for each provider.

{PROVIDER}_CLIENT_ID=your-client-id
{PROVIDER}_CLIENT_SECRET=your-client-secret

Example for Google:

GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret

And set callback URLs in your OAuth provider settings: {base url}/api/auth/{provider}/callback.

For example, if your base URL is https://example.com, the callback URL for Google would be https://example.com/api/auth/google/callback.

  1. Add OAuth providers to your Auth configuration.
server/auth/config.ts
import type { AuthOptions } from '@/server/auth/types'
import { GoogleProvider } from '@/server/auth/providers/google'

export const authOptions = {
  google: new GoogleProvider(),
} satisfies AuthOptions

Manual Installation

You can find all the necessary code in our GitHub repository: https://github.com/tiesen243/yuki-ui/tree/main/registry/auth.