LogoRobo.js

Adapters

Built-in storage adapters for users, sessions, accounts, and passwords.

The plugin ships two storage adapters: Flashcore (zero-config default) and Prisma (for projects already using Prisma). Both implement the PasswordAdapter interface, which extends Auth.js's Adapter with password management methods.

Flashcore adapter

Setup

import { createFlashcoreAdapter } from '@robojs/auth'

const adapter = createFlashcoreAdapter({ secret: process.env.AUTH_SECRET! })
import { createFlashcoreAdapter } from '@robojs/auth'

const adapter = createFlashcoreAdapter({ secret: process.env.AUTH_SECRET! })

The only required option is secret, used for hashing verification tokens. When no adapter is passed to the plugin config, Flashcore is created automatically from the resolved secret.

Storage namespaces

NamespacePurpose
auth:usersUser records
auth:usersByEmailEmail-to-userId index
auth:accountsOAuth account records
auth:userAccountsPer-user account references
auth:sessionsSession records
auth:verificationVerification tokens (SHA-256 hashed)
auth:usersIndexPaginated user ID index
auth:passwordPassword hash records
auth:passwordUserByEmailPassword email-to-userId index

Pagination

import { listUsers, listUserIds } from '@robojs/auth'

// Full user records (page 0, 500 per page)
const { users, page, pageCount, total } = await listUsers()

// User IDs only (lighter)
const { ids } = await listUserIds(2)
import { listUsers, listUserIds } from '@robojs/auth'

// Full user records (page 0, 500 per page)
const { users, page, pageCount, total } = await listUsers()

// User IDs only (lighter)
const { ids } = await listUserIds(2)

Default page size is 500. Out-of-range pages return empty arrays with metadata.

Behavior notes

  • Email addresses are normalized to lowercase
  • User IDs auto-generated via nanoid(21) when not provided
  • Expired sessions are pruned on read
  • Verification tokens are hashed with SHA-256 before storage
  • Deleting a user cascades to accounts, sessions, passwords, and index entries

Prisma adapter

Setup

import { PrismaClient } from '@prisma/client'
import { createPrismaAdapter } from '@robojs/auth'

const prisma = new PrismaClient()
const adapter = createPrismaAdapter({
  client: prisma,
  secret: process.env.AUTH_SECRET!
})
import { PrismaClient } from '@prisma/client'
import { createPrismaAdapter } from '@robojs/auth'

const prisma = new PrismaClient()
const adapter = createPrismaAdapter({
  client: prisma,
  secret: process.env.AUTH_SECRET!
})

Requires @auth/prisma-adapter and @prisma/client installed in your project.

Options

OptionTypeDefaultDescription
clientPrismaClientRequiredInitialized Prisma client
secretstringRequiredToken hashing secret
models.passwordstring'password'Custom password model name

Schema additions

Add this model alongside the standard Auth.js Prisma schema:

model Password {
  id        String   @id @default(cuid())
  userId    String   @unique
  email     String   @unique
  hash      String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([email])
}

Run npx prisma migrate dev --name add-auth-passwords after updating the schema.

PostgreSQL users can use @db.Citext on the email field for native case-insensitive lookups. Other databases rely on the adapter's toLowerCase() normalization.

Pagination

import { listPrismaUsers, listPrismaUserIds } from '@robojs/auth'

const { users } = await listPrismaUsers(prisma)
const { ids } = await listPrismaUserIds(prisma, {
  page: 1,
  pageSize: 100,
  orderBy: { createdAt: 'desc' },
  where: { emailVerified: { not: null } }
})
import { listPrismaUsers, listPrismaUserIds } from '@robojs/auth'

const { users } = await listPrismaUsers(prisma)
const { ids } = await listPrismaUserIds(prisma, {
  page: 1,
  pageSize: 100,
  orderBy: { createdAt: 'desc' },
  where: { emailVerified: { not: null } }
})

Both functions accept page, pageSize, orderBy, and where parameters. Default page size: 500.

Auto-rehashing

The Prisma adapter automatically rehashes passwords on verify when Argon2 parameters change. The Flashcore adapter does not auto-rehash (manual migration needed).

PasswordAdapter interface

Both adapters implement this interface, which extends Auth.js's Adapter:

MethodDescription
createUserPassword({ userId, email, hash })Store a password hash
getUserPassword(userId)Retrieve the password record
findUserIdByEmail(email)Case-insensitive email lookup
deleteUserPassword(userId)Remove a password record
resetUserPassword({ userId, hash })Replace a password hash

Validate at runtime:

import { assertPasswordAdapter } from '@robojs/auth'

assertPasswordAdapter(myAdapter) // throws if methods are missing
import { assertPasswordAdapter } from '@robojs/auth'

assertPasswordAdapter(myAdapter) // throws if methods are missing

Switching adapters

config/plugins/robojs/auth.ts
import EmailPassword from '@robojs/auth/providers/email-password'
import { createFlashcoreAdapter } from '@robojs/auth'

const adapter = createFlashcoreAdapter({ secret: process.env.AUTH_SECRET! })

export default {
  adapter,
  providers: [EmailPassword({ adapter })]
}
config/plugins/robojs/auth.js
import EmailPassword from '@robojs/auth/providers/email-password'
import { createFlashcoreAdapter } from '@robojs/auth'

const adapter = createFlashcoreAdapter({ secret: process.env.AUTH_SECRET! })

export default {
  adapter,
  providers: [EmailPassword({ adapter })]
}
config/plugins/robojs/auth.ts
    import { PrismaClient } from '@prisma/client'
    import EmailPassword from '@robojs/auth/providers/email-password'
    import { createPrismaAdapter } from '@robojs/auth'

    const prisma = new PrismaClient()
    const adapter = createPrismaAdapter({ client: prisma, secret: process.env.AUTH_SECRET! })

    export default {
      adapter,
      providers: [EmailPassword({ adapter })]
    }
config/plugins/robojs/auth.js
    import { PrismaClient } from '@prisma/client'
    import EmailPassword from '@robojs/auth/providers/email-password'
    import { createPrismaAdapter } from '@robojs/auth'

    const prisma = new PrismaClient()
    const adapter = createPrismaAdapter({ client: prisma, secret: process.env.AUTH_SECRET! })

    export default {
      adapter,
      providers: [EmailPassword({ adapter })]
    }

Next steps

On this page