npm package: @netizen-experience/auth
Description: Improved version of DynamoDBAdapter from existing one in next-auth with more complete helper functions, and functions to handle credentials account
Author: Netizen Experience
Latest version: 0.1.14

# Auth

Adding feature to dynamoDB adapter from next-auth

## Table of Contents

- [Dependency](#dependency)
- [Functions](#functions)
  - [ImprovedDynamoDBAdapter](#improved-dynamodb-adapter)
    - [getAccount](#getaccount)
    - [updateAccount](#updateaccount)
    - [createUserWithCredentials](#createuserwithcredentials)
  - [CredentialsProvider](#credentials-provider)
  - [NodemailerProvider](#nodemailer-provider)
  - [Setting up Auth.js](#setting-up-authjs)
- [Types and Interfaces](#types-and-interfaces)
  - [Adapter](#adapter)
  - [AdapterAccount](#adapteraccount)
  - [ClientAdapterUser](#clientadapteruser)
  - [CredentialsFields](#credentialsfields)
  - [BaseClientCredentials](#baseclientcredentials)
  - [BaseSchema](#baseschema)
  - [MailOptions](#mailoptions)
  - [EmailTemplateFunction](#emailtemplatefunction)

## Dependency

Add the following peer dependency to your project

```bash
npm i \
	"@auth/core@^0.40.0" \
	"@auth/dynamodb-adapter@^2.8.0" \
	"@aws-sdk/client-dynamodb@>=3.758.0" \
	"@aws-sdk/client-sesv2@>=3.684.0" \
	"@aws-sdk/lib-dynamodb@>=3.758.0" \
	"aws-cdk-lib@^2.183.0" \
	"constructs@^10.4.2" \
	"next@^15.0.0" \
	"next-auth@^5.0.0-beta.25" \
	"nodemailer@^6.10.0" \
	"react@^19.0.0" \
	"react-dom@^19.0.0" \
	"zod@^3.24.2"
```

## Functions

### ImprovedDynamoDBAdapter

This library extends the existing DynamoDB adapter from Auth.js (`@auth/dynamodb-adapter`) to include more helper functions to interact with the DynamoDB table used by Auth.js and to handle and persist credential account.

To instantiate the adapter:

```ts
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb";
import { ImprovedDynamoDBAdapter } from "@netizen-experience/auth-lib";

const document = DynamoDBDocument.from(new DynamoDB());
const adapter = ImprovedDynamoDBAdapter(document, { tableName: "next-auth" });
```

This library added methods that were in the `Adapter` interface but were not implemented in the original `@auth/dynamodb-adapter`, as well as new methods to help in handling credentials provider:

#### getAccount

- Get account by provider account id and provider. If an account is not found, the adapter must return null. (See [Auth.js documentation](https://authjs.dev/reference/core/adapters#getaccount) for implementation details.)

#### updateAccount

Updates attributes of an existing account in the database and returns it. Requires `userId`, `provider`, and `providerAccountId` to identify the account, then updates the other attributes passed in for the account entry. If the account does not exist, returns null.

**Parameters**

| Parameter | Type                                                                                                                                                                                                                      |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| data      | `Omit`<`Partial`<[`AdapterAccount`](#adapteraccount)>, `"userId"` \| `"provider"` \| `"providerAccountId"`> & `Required`<`Pick`<[`AdapterAccout`](#adapteraccount), `"userId"` \| `"provider"` \| `"providerAccountId"`>> |

**Returns**

- `Promise`<[`AdapterAccount`](#adapteraccount) \| `null`>

**Example**

Say you want to have a field `name` in [`AdapterAccount`](#adapteraccount) to store the name of the user. You can update the account with the new name like so:

```ts
// This would return the updated account object if the account exists.
await adapter.updateAccount({
  userId: "<user-id>",
  provider: "credentials",
  providerAccountId: "<provider-account-id>",
  name: "John Doe",
});
```

#### createUserWithCredentials

Creates a user under Credentials provider, or links a Credentials account to an existing user, and returns the user object. Requires `email`, `password`, and whatever other fields you have in your [`AdapterUser`](https://authjs.dev/reference/core/adapters#adapteruser) type excluding `id` and `emailVerified` that are optional.

**Parameters**

| Parameter | Type                                                                                                                                                                                                                                                                                 |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| data      | `Omit`<[`AdapterUser`](https://authjs.dev/reference/core/adapters#adapteruser), `"id"` \| `"emailVerified"`> & `Partial`<`Pick`<[`AdapterUser`](https://authjs.dev/reference/core/adapters#adapteruser), `"id"` \| `"emailVerified">>` & { `email`: `string`; `password`: `string` } |

**Returns**

- `Promise`<[`AdapterUser`](https://authjs.dev/reference/core/adapters#adapteruser) \| `null`>

**Example**

```ts
await adapter.createUserWithCredentials({
  email: "john.doe@example.com",
  password: "password",
  name: "John Doe",
  image: "https://example.com/john-doe.jpg",
  ... // other fields
});
```

### Credentials Provider

Set up credentials provider to use with Auth.js using the `setupCredentialsProvider` function.

**Parameters**

Pass the following fields as an object to the `setupCredentialsProvider` function:

| Attribute | Type                                         | Description                                                                                                         |
| --------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| adapter   | [`Adapter`](#adapter)                        | The adapter to use with the credentials provider that needs to have both `getUserByEmail` and `getAccount` methods. |
| fields    | [`CredentialsFields`](#credentialsfields)    | The input fields needed for credentials account.                                                                    |
| schema    | `Schema` extends [`BaseSchema`](#baseschema) | The Zod schema to validate the input fields.                                                                        |

**Example**

```ts
const CredentialsProvider = setupCredentialsProvider({
  adapter: ImprovedDynamoDBAdapter(... /* adapter options */),
  fields: {
    email: { label: "Email", type: "email", placeholder: "example@example.com" },
    password: { label: "Password", type: "password" },
    ... // other fields to create a credential account in your application
  },
  schema: z.object({
    email: z.string().email(),
    password: z.string().min(8)
    ... // other fields schema to validate the input fields
  }),
});

const authResult = NextAuth({
  providers: [CredentialsProvider, ... /* other providers */],
  ... // other options
})
```

### Nodemailer Provider

Set up nodemailer provider to use with Auth.js using the `setupNodemailerProvider` function.

**Parameters**

Pass the following fields as an object to the `setupNodemailerProvider` function:

| Attribute | Type                                                                                              | Description                                                                     |
| --------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| client    | [`SESv2Client`](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sesv2/)             | The SESv2Client instance                                                        |
| config    | [`NodemailerUserConfig`](https://authjs.dev/reference/core/providers/nodemailer#nodemailerconfig) | The nodemailer provider config                                                  |
| mail      | [`MailOptions`](#mailoptions)                                                                     | The mail templates and other nodemailer's mail options for verification request |

**Examples**

```ts
const NodemailerProvider = setupNodemailerProvider({
  client: new SESv2Client(),
  config: {
    from: "Support <support@example.com>",
    secret: process.env.NODEMAILER_SECRET, // secret to encrypt the token
    ... /* other necessary nodemailer config */
  },
  mail: {
    subject: ({ host }) => `Sign in to ${host}`,
    text: ({ url, host }) => `Sign in to ${host}, click this link: ${url}`,
    html: ({ url, host, }) => `<p>Sign in to ${host}, click <a href='${url}'>here</a>.</p>`,
  },
});

const authResult = NextAuth({
  providers: [NodemailerProvider, ... /* other providers */],
  ... // other options
});
```

### Setting up Auth.js

Assuming you have go through the above sections, you can now set up Auth.js with the providers you have set up.

```ts
// Say you have set up adapter, CredentialsProvider, and NodemailerProvider as shown above
const { auth, handlers, signIn, signOut } = NextAuth({
  providers: [CredentialsProvider, NodemailerProvider, ... /* other providers */],
  adapter,
});
```

## Types and Interfaces

### Adapter

Extended from [`@auth/core/adapters`](https://authjs.dev/reference/core/adapters), with additional methods `updateAccount` and `createUserWithCredentials`. See [`ImprovedDynamoDBAdapter`](#ImprovedDynamoDBAdapter).

### AdapterAccount

Extended from [`@auth/core/adapters`](https://authjs.dev/reference/core/adapters#adapteraccount), with additional attributes `pwHash` and `salt`. These are tailored to be used with the [`Credentials`](https://authjs.dev/getting-started/providers/credentials) provider to store hashed passwords and salts.

New attributes:

- `pwHash`: `string | undefined`
- `salt`: `string | undefined`

### ClientAdapterUser

Represents a user object on the application client side with optional fields. This type is derived from [`AdapterUser`](https://authjs.dev/reference/core/adapters#adapteruser) by making `emailVerified` and `id` properties optional. It is used to represent the user in the application where some fields might not be required.

- `Omit`<[`AdapterUser`](https://authjs.dev/reference/core/adapters#adapteruser), `"emailVerified"` \| `"id"`> & `Partial`<`Pick`<[`AdapterUser`](https://authjs.dev/reference/core/adapters#adapteruser), `"emailVerified"` \| `"id"`>>;

### CredentialsFields

Represents the fields required for `credentials` attribute in [`Credentials`](https://authjs.dev/getting-started/providers/credentials) provider, but this type enforces `email` and `password` to be required, and the rest of fields are optional and can be any of the fields in [`ClientAdapterUser`](#clientadapteruser).

- `Omit`<`Record`<`keyof` [`ClientAdapterUser`](#clientadapteruser), [`CredentialInput`](https://authjs.dev/reference/core/providers/credentials#credentialinput)>, `"email"`> & `Required`<`Pick`<[`ClientAdapterUser`](#clientadapteruser), `"email"`>> & { `password`: [`CredentialInput`](https://authjs.dev/reference/core/providers/credentials#credentialinput) };

### BaseClientCredentials

Base type for credentials input type used in the application. This type is used to represent the credentials in the application where `email` and `password` are required.

- { `email`: `string`; `password`: `string` };

### BaseSchema

Base Zod schema for credentials input type used in the application. This type is used to validate the credentials in the application where `email` and `password` are required.

- [`z.ZodType`](https://zod.dev/?id=zodtype-with-zodeffects)<[`BaseClientCredentials`](#baseclientcredentials) & `Record`<`string`, [`NativeAttributeValue`](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-lib-dynamodb/TypeAlias/NativeAttributeValue/)>>;

### MailOptions

Represents the object that needs to be passed to [`setupNodemailerProvider`](#nodemailer-provider) function. It contains the options from nodemailer `Mail` and the email templates functions to generate verification request email.

- `Omit`<[`Mail.Options`](https://nodemailer.com/message), `"to"` \| `"from"` \| `"subject"` \| `"html"` \| `"text"`> & { `subject?`: [`EmailTemplateFunction`](#emailtemplatefunction); `html?`: [`EmailTemplateFunction`](#emailtemplatefunction); `text?`: [`EmailTemplateFunction`](#emailtemplatefunction) };

### EmailTemplateFunction

Represents a function that generates an email template. This function takes an object with `url`, `host`, and `identifier` properties and returns a string. This is the parameter type for `subject`, `html`, and `text` properties in [`MailOptions`](#mailoptions). See [Auth.js documentation](https://authjs.dev/getting-started/providers/nodemailer#customization) for more details.

- (`params`: { `url`: `string`; `host?`: `string`; `identifier?`: `string` }) => `string`;