@auth/dynamodb-adapter 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/index.d.ts +3 -179
- package/index.d.ts.map +1 -1
- package/index.js +3 -183
- package/package.json +2 -2
- package/src/index.ts +9 -191
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<img src="https://img.shields.io/npm/dm/@auth/dynamodb-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
|
19
19
|
</a>
|
|
20
20
|
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
|
21
|
-
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="
|
|
21
|
+
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="GitHub Stars" />
|
|
22
22
|
</a>
|
|
23
23
|
</p>
|
|
24
24
|
</p>
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", padding: "16px"}}>
|
|
3
|
-
* <p
|
|
3
|
+
* <p>Official <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html">DynamoDB</a> adapter for Auth.js / NextAuth.js.</p>
|
|
4
4
|
* <a href="https://docs.aws.amazon.com/dynamodb/index.html">
|
|
5
5
|
* <img style={{display: "block"}} src="https://authjs.dev/img/adapters/dynamodb.png" width="48"/>
|
|
6
6
|
* </a>
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* @module @auth/dynamodb-adapter
|
|
16
16
|
*/
|
|
17
17
|
import type { DynamoDBDocument } from "@aws-sdk/lib-dynamodb";
|
|
18
|
-
import type
|
|
18
|
+
import { type Adapter } from "@auth/core/adapters";
|
|
19
19
|
export interface DynamoDBAdapterOptions {
|
|
20
20
|
tableName?: string;
|
|
21
21
|
partitionKey?: string;
|
|
@@ -24,185 +24,9 @@ export interface DynamoDBAdapterOptions {
|
|
|
24
24
|
indexPartitionKey?: string;
|
|
25
25
|
indexSortKey?: string;
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
* ## Setup
|
|
29
|
-
*
|
|
30
|
-
* By default, the adapter expects a table with a partition key `pk` and a sort key `sk`, as well as a global secondary index named `GSI1` with `GSI1PK` as partition key and `GSI1SK` as sorting key. To automatically delete sessions and verification requests after they expire using [dynamodb TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) you should [enable the TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/time-to-live-ttl-how-to.html) with attribute name 'expires'. You can set whatever you want as the table name and the billing method.
|
|
31
|
-
* You can find the full schema in the table structure section below.
|
|
32
|
-
*
|
|
33
|
-
* ### Configuring Auth.js
|
|
34
|
-
*
|
|
35
|
-
* You need to pass `DynamoDBDocument` client from the modular [`aws-sdk`](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/dynamodb-example-dynamodb-utilities.html) v3 to the adapter.
|
|
36
|
-
* The default table name is `next-auth`, but you can customise that by passing `{ tableName: 'your-table-name' }` as the second parameter in the adapter.
|
|
37
|
-
*
|
|
38
|
-
* ```js title="pages/api/auth/[...nextauth].js"
|
|
39
|
-
* import { DynamoDB, DynamoDBClientConfig } from "@aws-sdk/client-dynamodb"
|
|
40
|
-
* import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
|
|
41
|
-
* import NextAuth from "next-auth";
|
|
42
|
-
* import Providers from "next-auth/providers";
|
|
43
|
-
* import { DynamoDBAdapter } from "@auth/dynamodb-adapter"
|
|
44
|
-
*
|
|
45
|
-
* const config: DynamoDBClientConfig = {
|
|
46
|
-
* credentials: {
|
|
47
|
-
* accessKeyId: process.env.NEXT_AUTH_AWS_ACCESS_KEY,
|
|
48
|
-
* secretAccessKey: process.env.NEXT_AUTH_AWS_SECRET_KEY,
|
|
49
|
-
* },
|
|
50
|
-
* region: process.env.NEXT_AUTH_AWS_REGION,
|
|
51
|
-
* };
|
|
52
|
-
*
|
|
53
|
-
* const client = DynamoDBDocument.from(new DynamoDB(config), {
|
|
54
|
-
* marshallOptions: {
|
|
55
|
-
* convertEmptyValues: true,
|
|
56
|
-
* removeUndefinedValues: true,
|
|
57
|
-
* convertClassInstanceToMap: true,
|
|
58
|
-
* },
|
|
59
|
-
* })
|
|
60
|
-
*
|
|
61
|
-
* export default NextAuth({
|
|
62
|
-
* // Configure one or more authentication providers
|
|
63
|
-
* providers: [
|
|
64
|
-
* Providers.GitHub({
|
|
65
|
-
* clientId: process.env.GITHUB_ID,
|
|
66
|
-
* clientSecret: process.env.GITHUB_SECRET,
|
|
67
|
-
* }),
|
|
68
|
-
* Providers.Email({
|
|
69
|
-
* server: process.env.EMAIL_SERVER,
|
|
70
|
-
* from: process.env.EMAIL_FROM,
|
|
71
|
-
* }),
|
|
72
|
-
* // ...add more providers here
|
|
73
|
-
* ],
|
|
74
|
-
* adapter: DynamoDBAdapter(
|
|
75
|
-
* client
|
|
76
|
-
* ),
|
|
77
|
-
* });
|
|
78
|
-
* ```
|
|
79
|
-
*
|
|
80
|
-
* (AWS secrets start with `NEXT_AUTH_` in order to not conflict with [Vercel's reserved environment variables](https://vercel.com/docs/environment-variables#reserved-environment-variables).)
|
|
81
|
-
*
|
|
82
|
-
* ## AWS Credentials
|
|
83
|
-
*
|
|
84
|
-
* :::note
|
|
85
|
-
* Always follow the **principle of least privilege** when giving access to AWS
|
|
86
|
-
* services/resources -> identities should only be permitted to perform the
|
|
87
|
-
* smallest set of actions necessary to fulfill a specific task.
|
|
88
|
-
* :::
|
|
89
|
-
*
|
|
90
|
-
* 1. Open the [AWS console](https://console.aws.amazon.com/) and go to "IAM", then "Users".
|
|
91
|
-
* 2. Create a new user. The purpose of this user is to give programmatic access to DynamoDB.
|
|
92
|
-
* 3. Create an Access Key and then copy Key ID and Secret to your `.env`/`.env.local` file.
|
|
93
|
-
* 4. Select "Add Permission" and "Create Inline Policy".
|
|
94
|
-
* 5. Copy the JSON below into the JSON input and replace `region`, `account_id` and `table_name` with your values.
|
|
95
|
-
*
|
|
96
|
-
* ```json
|
|
97
|
-
* {
|
|
98
|
-
* "Version": "2012-10-17",
|
|
99
|
-
* "Statement": [
|
|
100
|
-
* {
|
|
101
|
-
* "Sid": "DynamoDBAccess",
|
|
102
|
-
* "Effect": "Allow",
|
|
103
|
-
* "Action": [
|
|
104
|
-
* "dynamodb:BatchGetItem",
|
|
105
|
-
* "dynamodb:BatchWriteItem",
|
|
106
|
-
* "dynamodb:Describe*",
|
|
107
|
-
* "dynamodb:List*",
|
|
108
|
-
* "dynamodb:PutItem",
|
|
109
|
-
* "dynamodb:DeleteItem",
|
|
110
|
-
* "dynamodb:GetItem",
|
|
111
|
-
* "dynamodb:Scan",
|
|
112
|
-
* "dynamodb:Query",
|
|
113
|
-
* "dynamodb:UpdateItem"
|
|
114
|
-
* ],
|
|
115
|
-
* "Resource": [
|
|
116
|
-
* "arn:aws:dynamodb:{region}:{account_id}:table/{table_name}",
|
|
117
|
-
* "arn:aws:dynamodb:{region}:{account_id}:table/{table_name}/index/GSI1"
|
|
118
|
-
* ]
|
|
119
|
-
* }
|
|
120
|
-
* ]
|
|
121
|
-
* }
|
|
122
|
-
* ```
|
|
123
|
-
*
|
|
124
|
-
* ## Advanced usage
|
|
125
|
-
*
|
|
126
|
-
* ### Default schema
|
|
127
|
-
*
|
|
128
|
-
* The table respects the single table design pattern. This has many advantages:
|
|
129
|
-
*
|
|
130
|
-
* - Only one table to manage, monitor and provision.
|
|
131
|
-
* - Querying relations is faster than with multi-table schemas (for eg. retrieving all sessions for a user).
|
|
132
|
-
* - Only one table needs to be replicated if you want to go multi-region.
|
|
133
|
-
*
|
|
134
|
-
* > This schema is adapted for use in DynamoDB and based upon our main [schema](https://authjs.dev/reference/core/adapters#models)
|
|
135
|
-
*
|
|
136
|
-
* 
|
|
137
|
-
*
|
|
138
|
-
* You can create this table with infrastructure as code using [`aws-cdk`](https://github.com/aws/aws-cdk) with the following table definition:
|
|
139
|
-
*
|
|
140
|
-
* ```js title="stack.ts"
|
|
141
|
-
* new dynamodb.Table(this, `NextAuthTable`, {
|
|
142
|
-
* tableName: "next-auth",
|
|
143
|
-
* partitionKey: { name: "pk", type: dynamodb.AttributeType.STRING },
|
|
144
|
-
* sortKey: { name: "sk", type: dynamodb.AttributeType.STRING },
|
|
145
|
-
* timeToLiveAttribute: "expires",
|
|
146
|
-
* }).addGlobalSecondaryIndex({
|
|
147
|
-
* indexName: "GSI1",
|
|
148
|
-
* partitionKey: { name: "GSI1PK", type: dynamodb.AttributeType.STRING },
|
|
149
|
-
* sortKey: { name: "GSI1SK", type: dynamodb.AttributeType.STRING },
|
|
150
|
-
* })
|
|
151
|
-
* ```
|
|
152
|
-
*
|
|
153
|
-
* Alternatively, you can use this cloudformation template:
|
|
154
|
-
*
|
|
155
|
-
* ```yaml title=cloudformation.yaml
|
|
156
|
-
* NextAuthTable:
|
|
157
|
-
* Type: "AWS::DynamoDB::Table"
|
|
158
|
-
* Properties:
|
|
159
|
-
* TableName: next-auth
|
|
160
|
-
* AttributeDefinitions:
|
|
161
|
-
* - AttributeName: pk
|
|
162
|
-
* AttributeType: S
|
|
163
|
-
* - AttributeName: sk
|
|
164
|
-
* AttributeType: S
|
|
165
|
-
* - AttributeName: GSI1PK
|
|
166
|
-
* AttributeType: S
|
|
167
|
-
* - AttributeName: GSI1SK
|
|
168
|
-
* AttributeType: S
|
|
169
|
-
* KeySchema:
|
|
170
|
-
* - AttributeName: pk
|
|
171
|
-
* KeyType: HASH
|
|
172
|
-
* - AttributeName: sk
|
|
173
|
-
* KeyType: RANGE
|
|
174
|
-
* GlobalSecondaryIndexes:
|
|
175
|
-
* - IndexName: GSI1
|
|
176
|
-
* Projection:
|
|
177
|
-
* ProjectionType: ALL
|
|
178
|
-
* KeySchema:
|
|
179
|
-
* - AttributeName: GSI1PK
|
|
180
|
-
* KeyType: HASH
|
|
181
|
-
* - AttributeName: GSI1SK
|
|
182
|
-
* KeyType: RANGE
|
|
183
|
-
* TimeToLiveSpecification:
|
|
184
|
-
* AttributeName: expires
|
|
185
|
-
* Enabled: true
|
|
186
|
-
* ```
|
|
187
|
-
*
|
|
188
|
-
* ### Using a custom schema
|
|
189
|
-
*
|
|
190
|
-
* You can configure your custom table schema by passing the `options` key to the adapter constructor:
|
|
191
|
-
*
|
|
192
|
-
* ```js
|
|
193
|
-
* const adapter = DynamoDBAdapter(client, {
|
|
194
|
-
* tableName: "custom-table-name",
|
|
195
|
-
* partitionKey: "custom-pk",
|
|
196
|
-
* sortKey: "custom-sk",
|
|
197
|
-
* indexName: "custom-index-name",
|
|
198
|
-
* indexPartitionKey: "custom-index-pk",
|
|
199
|
-
* indexSortKey: "custom-index-sk",
|
|
200
|
-
* })
|
|
201
|
-
* ```
|
|
202
|
-
**/
|
|
203
27
|
export declare function DynamoDBAdapter(client: DynamoDBDocument, options?: DynamoDBAdapterOptions): Adapter;
|
|
204
28
|
declare const format: {
|
|
205
|
-
/** Takes a plain old JavaScript object and turns it into a
|
|
29
|
+
/** Takes a plain old JavaScript object and turns it into a DynamoDB object */
|
|
206
30
|
to(object: Record<string, any>): Record<string, unknown>;
|
|
207
31
|
/** Takes a Dynamo object and returns a plain old JavaScript object */
|
|
208
32
|
from<T = Record<string, unknown>>(object?: Record<string, any>): T | null;
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,KAAK,OAAO,EAMb,MAAM,qBAAqB,CAAA;AAE5B,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,EACxB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CA+ST;AAED,QAAA,MAAM,MAAM;IACV,8EAA8E;eACnE,OAAO,MAAM,EAAE,GAAG,CAAC;IAY9B,sEAAsE;+CAC3B,OAAO,MAAM,EAAE,GAAG,CAAC;CAsB/D,CAAA;AAED,iBAAS,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;IAC9D,gBAAgB,EAAE,MAAM,CAAA;IACxB,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChD,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnD,CAgBA;AAED,OAAO,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAA"}
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", padding: "16px"}}>
|
|
3
|
-
* <p
|
|
3
|
+
* <p>Official <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html">DynamoDB</a> adapter for Auth.js / NextAuth.js.</p>
|
|
4
4
|
* <a href="https://docs.aws.amazon.com/dynamodb/index.html">
|
|
5
5
|
* <img style={{display: "block"}} src="https://authjs.dev/img/adapters/dynamodb.png" width="48"/>
|
|
6
6
|
* </a>
|
|
@@ -14,182 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @module @auth/dynamodb-adapter
|
|
16
16
|
*/
|
|
17
|
-
|
|
18
|
-
* ## Setup
|
|
19
|
-
*
|
|
20
|
-
* By default, the adapter expects a table with a partition key `pk` and a sort key `sk`, as well as a global secondary index named `GSI1` with `GSI1PK` as partition key and `GSI1SK` as sorting key. To automatically delete sessions and verification requests after they expire using [dynamodb TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) you should [enable the TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/time-to-live-ttl-how-to.html) with attribute name 'expires'. You can set whatever you want as the table name and the billing method.
|
|
21
|
-
* You can find the full schema in the table structure section below.
|
|
22
|
-
*
|
|
23
|
-
* ### Configuring Auth.js
|
|
24
|
-
*
|
|
25
|
-
* You need to pass `DynamoDBDocument` client from the modular [`aws-sdk`](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/dynamodb-example-dynamodb-utilities.html) v3 to the adapter.
|
|
26
|
-
* The default table name is `next-auth`, but you can customise that by passing `{ tableName: 'your-table-name' }` as the second parameter in the adapter.
|
|
27
|
-
*
|
|
28
|
-
* ```js title="pages/api/auth/[...nextauth].js"
|
|
29
|
-
* import { DynamoDB, DynamoDBClientConfig } from "@aws-sdk/client-dynamodb"
|
|
30
|
-
* import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
|
|
31
|
-
* import NextAuth from "next-auth";
|
|
32
|
-
* import Providers from "next-auth/providers";
|
|
33
|
-
* import { DynamoDBAdapter } from "@auth/dynamodb-adapter"
|
|
34
|
-
*
|
|
35
|
-
* const config: DynamoDBClientConfig = {
|
|
36
|
-
* credentials: {
|
|
37
|
-
* accessKeyId: process.env.NEXT_AUTH_AWS_ACCESS_KEY,
|
|
38
|
-
* secretAccessKey: process.env.NEXT_AUTH_AWS_SECRET_KEY,
|
|
39
|
-
* },
|
|
40
|
-
* region: process.env.NEXT_AUTH_AWS_REGION,
|
|
41
|
-
* };
|
|
42
|
-
*
|
|
43
|
-
* const client = DynamoDBDocument.from(new DynamoDB(config), {
|
|
44
|
-
* marshallOptions: {
|
|
45
|
-
* convertEmptyValues: true,
|
|
46
|
-
* removeUndefinedValues: true,
|
|
47
|
-
* convertClassInstanceToMap: true,
|
|
48
|
-
* },
|
|
49
|
-
* })
|
|
50
|
-
*
|
|
51
|
-
* export default NextAuth({
|
|
52
|
-
* // Configure one or more authentication providers
|
|
53
|
-
* providers: [
|
|
54
|
-
* Providers.GitHub({
|
|
55
|
-
* clientId: process.env.GITHUB_ID,
|
|
56
|
-
* clientSecret: process.env.GITHUB_SECRET,
|
|
57
|
-
* }),
|
|
58
|
-
* Providers.Email({
|
|
59
|
-
* server: process.env.EMAIL_SERVER,
|
|
60
|
-
* from: process.env.EMAIL_FROM,
|
|
61
|
-
* }),
|
|
62
|
-
* // ...add more providers here
|
|
63
|
-
* ],
|
|
64
|
-
* adapter: DynamoDBAdapter(
|
|
65
|
-
* client
|
|
66
|
-
* ),
|
|
67
|
-
* });
|
|
68
|
-
* ```
|
|
69
|
-
*
|
|
70
|
-
* (AWS secrets start with `NEXT_AUTH_` in order to not conflict with [Vercel's reserved environment variables](https://vercel.com/docs/environment-variables#reserved-environment-variables).)
|
|
71
|
-
*
|
|
72
|
-
* ## AWS Credentials
|
|
73
|
-
*
|
|
74
|
-
* :::note
|
|
75
|
-
* Always follow the **principle of least privilege** when giving access to AWS
|
|
76
|
-
* services/resources -> identities should only be permitted to perform the
|
|
77
|
-
* smallest set of actions necessary to fulfill a specific task.
|
|
78
|
-
* :::
|
|
79
|
-
*
|
|
80
|
-
* 1. Open the [AWS console](https://console.aws.amazon.com/) and go to "IAM", then "Users".
|
|
81
|
-
* 2. Create a new user. The purpose of this user is to give programmatic access to DynamoDB.
|
|
82
|
-
* 3. Create an Access Key and then copy Key ID and Secret to your `.env`/`.env.local` file.
|
|
83
|
-
* 4. Select "Add Permission" and "Create Inline Policy".
|
|
84
|
-
* 5. Copy the JSON below into the JSON input and replace `region`, `account_id` and `table_name` with your values.
|
|
85
|
-
*
|
|
86
|
-
* ```json
|
|
87
|
-
* {
|
|
88
|
-
* "Version": "2012-10-17",
|
|
89
|
-
* "Statement": [
|
|
90
|
-
* {
|
|
91
|
-
* "Sid": "DynamoDBAccess",
|
|
92
|
-
* "Effect": "Allow",
|
|
93
|
-
* "Action": [
|
|
94
|
-
* "dynamodb:BatchGetItem",
|
|
95
|
-
* "dynamodb:BatchWriteItem",
|
|
96
|
-
* "dynamodb:Describe*",
|
|
97
|
-
* "dynamodb:List*",
|
|
98
|
-
* "dynamodb:PutItem",
|
|
99
|
-
* "dynamodb:DeleteItem",
|
|
100
|
-
* "dynamodb:GetItem",
|
|
101
|
-
* "dynamodb:Scan",
|
|
102
|
-
* "dynamodb:Query",
|
|
103
|
-
* "dynamodb:UpdateItem"
|
|
104
|
-
* ],
|
|
105
|
-
* "Resource": [
|
|
106
|
-
* "arn:aws:dynamodb:{region}:{account_id}:table/{table_name}",
|
|
107
|
-
* "arn:aws:dynamodb:{region}:{account_id}:table/{table_name}/index/GSI1"
|
|
108
|
-
* ]
|
|
109
|
-
* }
|
|
110
|
-
* ]
|
|
111
|
-
* }
|
|
112
|
-
* ```
|
|
113
|
-
*
|
|
114
|
-
* ## Advanced usage
|
|
115
|
-
*
|
|
116
|
-
* ### Default schema
|
|
117
|
-
*
|
|
118
|
-
* The table respects the single table design pattern. This has many advantages:
|
|
119
|
-
*
|
|
120
|
-
* - Only one table to manage, monitor and provision.
|
|
121
|
-
* - Querying relations is faster than with multi-table schemas (for eg. retrieving all sessions for a user).
|
|
122
|
-
* - Only one table needs to be replicated if you want to go multi-region.
|
|
123
|
-
*
|
|
124
|
-
* > This schema is adapted for use in DynamoDB and based upon our main [schema](https://authjs.dev/reference/core/adapters#models)
|
|
125
|
-
*
|
|
126
|
-
* 
|
|
127
|
-
*
|
|
128
|
-
* You can create this table with infrastructure as code using [`aws-cdk`](https://github.com/aws/aws-cdk) with the following table definition:
|
|
129
|
-
*
|
|
130
|
-
* ```js title="stack.ts"
|
|
131
|
-
* new dynamodb.Table(this, `NextAuthTable`, {
|
|
132
|
-
* tableName: "next-auth",
|
|
133
|
-
* partitionKey: { name: "pk", type: dynamodb.AttributeType.STRING },
|
|
134
|
-
* sortKey: { name: "sk", type: dynamodb.AttributeType.STRING },
|
|
135
|
-
* timeToLiveAttribute: "expires",
|
|
136
|
-
* }).addGlobalSecondaryIndex({
|
|
137
|
-
* indexName: "GSI1",
|
|
138
|
-
* partitionKey: { name: "GSI1PK", type: dynamodb.AttributeType.STRING },
|
|
139
|
-
* sortKey: { name: "GSI1SK", type: dynamodb.AttributeType.STRING },
|
|
140
|
-
* })
|
|
141
|
-
* ```
|
|
142
|
-
*
|
|
143
|
-
* Alternatively, you can use this cloudformation template:
|
|
144
|
-
*
|
|
145
|
-
* ```yaml title=cloudformation.yaml
|
|
146
|
-
* NextAuthTable:
|
|
147
|
-
* Type: "AWS::DynamoDB::Table"
|
|
148
|
-
* Properties:
|
|
149
|
-
* TableName: next-auth
|
|
150
|
-
* AttributeDefinitions:
|
|
151
|
-
* - AttributeName: pk
|
|
152
|
-
* AttributeType: S
|
|
153
|
-
* - AttributeName: sk
|
|
154
|
-
* AttributeType: S
|
|
155
|
-
* - AttributeName: GSI1PK
|
|
156
|
-
* AttributeType: S
|
|
157
|
-
* - AttributeName: GSI1SK
|
|
158
|
-
* AttributeType: S
|
|
159
|
-
* KeySchema:
|
|
160
|
-
* - AttributeName: pk
|
|
161
|
-
* KeyType: HASH
|
|
162
|
-
* - AttributeName: sk
|
|
163
|
-
* KeyType: RANGE
|
|
164
|
-
* GlobalSecondaryIndexes:
|
|
165
|
-
* - IndexName: GSI1
|
|
166
|
-
* Projection:
|
|
167
|
-
* ProjectionType: ALL
|
|
168
|
-
* KeySchema:
|
|
169
|
-
* - AttributeName: GSI1PK
|
|
170
|
-
* KeyType: HASH
|
|
171
|
-
* - AttributeName: GSI1SK
|
|
172
|
-
* KeyType: RANGE
|
|
173
|
-
* TimeToLiveSpecification:
|
|
174
|
-
* AttributeName: expires
|
|
175
|
-
* Enabled: true
|
|
176
|
-
* ```
|
|
177
|
-
*
|
|
178
|
-
* ### Using a custom schema
|
|
179
|
-
*
|
|
180
|
-
* You can configure your custom table schema by passing the `options` key to the adapter constructor:
|
|
181
|
-
*
|
|
182
|
-
* ```js
|
|
183
|
-
* const adapter = DynamoDBAdapter(client, {
|
|
184
|
-
* tableName: "custom-table-name",
|
|
185
|
-
* partitionKey: "custom-pk",
|
|
186
|
-
* sortKey: "custom-sk",
|
|
187
|
-
* indexName: "custom-index-name",
|
|
188
|
-
* indexPartitionKey: "custom-index-pk",
|
|
189
|
-
* indexSortKey: "custom-index-sk",
|
|
190
|
-
* })
|
|
191
|
-
* ```
|
|
192
|
-
**/
|
|
17
|
+
import { isDate, } from "@auth/core/adapters";
|
|
193
18
|
export function DynamoDBAdapter(client, options) {
|
|
194
19
|
const TableName = options?.tableName ?? "next-auth";
|
|
195
20
|
const pk = options?.partitionKey ?? "pk";
|
|
@@ -485,13 +310,8 @@ export function DynamoDBAdapter(client, options) {
|
|
|
485
310
|
},
|
|
486
311
|
};
|
|
487
312
|
}
|
|
488
|
-
// https://github.com/honeinc/is-iso-date/blob/master/index.js
|
|
489
|
-
const isoDateRE = /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/;
|
|
490
|
-
function isDate(value) {
|
|
491
|
-
return value && isoDateRE.test(value) && !isNaN(Date.parse(value));
|
|
492
|
-
}
|
|
493
313
|
const format = {
|
|
494
|
-
/** Takes a plain old JavaScript object and turns it into a
|
|
314
|
+
/** Takes a plain old JavaScript object and turns it into a DynamoDB object */
|
|
495
315
|
to(object) {
|
|
496
316
|
const newObject = {};
|
|
497
317
|
for (const key in object) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@auth/dynamodb-adapter",
|
|
3
3
|
"repository": "https://github.com/nextauthjs/next-auth",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"description": "AWS DynamoDB adapter for next-auth.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"next-auth",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@aws-sdk/lib-dynamodb": "^3.36.1"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@auth/core": "0.
|
|
47
|
+
"@auth/core": "0.32.0"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"test:default": "vitest -c ../utils/vitest.config.ts",
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", padding: "16px"}}>
|
|
3
|
-
* <p
|
|
3
|
+
* <p>Official <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html">DynamoDB</a> adapter for Auth.js / NextAuth.js.</p>
|
|
4
4
|
* <a href="https://docs.aws.amazon.com/dynamodb/index.html">
|
|
5
5
|
* <img style={{display: "block"}} src="https://authjs.dev/img/adapters/dynamodb.png" width="48"/>
|
|
6
6
|
* </a>
|
|
@@ -19,12 +19,13 @@ import type {
|
|
|
19
19
|
BatchWriteCommandInput,
|
|
20
20
|
DynamoDBDocument,
|
|
21
21
|
} from "@aws-sdk/lib-dynamodb"
|
|
22
|
-
import
|
|
23
|
-
Adapter,
|
|
24
|
-
AdapterSession,
|
|
25
|
-
AdapterAccount,
|
|
26
|
-
AdapterUser,
|
|
27
|
-
VerificationToken,
|
|
22
|
+
import {
|
|
23
|
+
type Adapter,
|
|
24
|
+
type AdapterSession,
|
|
25
|
+
type AdapterAccount,
|
|
26
|
+
type AdapterUser,
|
|
27
|
+
type VerificationToken,
|
|
28
|
+
isDate,
|
|
28
29
|
} from "@auth/core/adapters"
|
|
29
30
|
|
|
30
31
|
export interface DynamoDBAdapterOptions {
|
|
@@ -36,182 +37,6 @@ export interface DynamoDBAdapterOptions {
|
|
|
36
37
|
indexSortKey?: string
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
/**
|
|
40
|
-
* ## Setup
|
|
41
|
-
*
|
|
42
|
-
* By default, the adapter expects a table with a partition key `pk` and a sort key `sk`, as well as a global secondary index named `GSI1` with `GSI1PK` as partition key and `GSI1SK` as sorting key. To automatically delete sessions and verification requests after they expire using [dynamodb TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) you should [enable the TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/time-to-live-ttl-how-to.html) with attribute name 'expires'. You can set whatever you want as the table name and the billing method.
|
|
43
|
-
* You can find the full schema in the table structure section below.
|
|
44
|
-
*
|
|
45
|
-
* ### Configuring Auth.js
|
|
46
|
-
*
|
|
47
|
-
* You need to pass `DynamoDBDocument` client from the modular [`aws-sdk`](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/dynamodb-example-dynamodb-utilities.html) v3 to the adapter.
|
|
48
|
-
* The default table name is `next-auth`, but you can customise that by passing `{ tableName: 'your-table-name' }` as the second parameter in the adapter.
|
|
49
|
-
*
|
|
50
|
-
* ```js title="pages/api/auth/[...nextauth].js"
|
|
51
|
-
* import { DynamoDB, DynamoDBClientConfig } from "@aws-sdk/client-dynamodb"
|
|
52
|
-
* import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
|
|
53
|
-
* import NextAuth from "next-auth";
|
|
54
|
-
* import Providers from "next-auth/providers";
|
|
55
|
-
* import { DynamoDBAdapter } from "@auth/dynamodb-adapter"
|
|
56
|
-
*
|
|
57
|
-
* const config: DynamoDBClientConfig = {
|
|
58
|
-
* credentials: {
|
|
59
|
-
* accessKeyId: process.env.NEXT_AUTH_AWS_ACCESS_KEY,
|
|
60
|
-
* secretAccessKey: process.env.NEXT_AUTH_AWS_SECRET_KEY,
|
|
61
|
-
* },
|
|
62
|
-
* region: process.env.NEXT_AUTH_AWS_REGION,
|
|
63
|
-
* };
|
|
64
|
-
*
|
|
65
|
-
* const client = DynamoDBDocument.from(new DynamoDB(config), {
|
|
66
|
-
* marshallOptions: {
|
|
67
|
-
* convertEmptyValues: true,
|
|
68
|
-
* removeUndefinedValues: true,
|
|
69
|
-
* convertClassInstanceToMap: true,
|
|
70
|
-
* },
|
|
71
|
-
* })
|
|
72
|
-
*
|
|
73
|
-
* export default NextAuth({
|
|
74
|
-
* // Configure one or more authentication providers
|
|
75
|
-
* providers: [
|
|
76
|
-
* Providers.GitHub({
|
|
77
|
-
* clientId: process.env.GITHUB_ID,
|
|
78
|
-
* clientSecret: process.env.GITHUB_SECRET,
|
|
79
|
-
* }),
|
|
80
|
-
* Providers.Email({
|
|
81
|
-
* server: process.env.EMAIL_SERVER,
|
|
82
|
-
* from: process.env.EMAIL_FROM,
|
|
83
|
-
* }),
|
|
84
|
-
* // ...add more providers here
|
|
85
|
-
* ],
|
|
86
|
-
* adapter: DynamoDBAdapter(
|
|
87
|
-
* client
|
|
88
|
-
* ),
|
|
89
|
-
* });
|
|
90
|
-
* ```
|
|
91
|
-
*
|
|
92
|
-
* (AWS secrets start with `NEXT_AUTH_` in order to not conflict with [Vercel's reserved environment variables](https://vercel.com/docs/environment-variables#reserved-environment-variables).)
|
|
93
|
-
*
|
|
94
|
-
* ## AWS Credentials
|
|
95
|
-
*
|
|
96
|
-
* :::note
|
|
97
|
-
* Always follow the **principle of least privilege** when giving access to AWS
|
|
98
|
-
* services/resources -> identities should only be permitted to perform the
|
|
99
|
-
* smallest set of actions necessary to fulfill a specific task.
|
|
100
|
-
* :::
|
|
101
|
-
*
|
|
102
|
-
* 1. Open the [AWS console](https://console.aws.amazon.com/) and go to "IAM", then "Users".
|
|
103
|
-
* 2. Create a new user. The purpose of this user is to give programmatic access to DynamoDB.
|
|
104
|
-
* 3. Create an Access Key and then copy Key ID and Secret to your `.env`/`.env.local` file.
|
|
105
|
-
* 4. Select "Add Permission" and "Create Inline Policy".
|
|
106
|
-
* 5. Copy the JSON below into the JSON input and replace `region`, `account_id` and `table_name` with your values.
|
|
107
|
-
*
|
|
108
|
-
* ```json
|
|
109
|
-
* {
|
|
110
|
-
* "Version": "2012-10-17",
|
|
111
|
-
* "Statement": [
|
|
112
|
-
* {
|
|
113
|
-
* "Sid": "DynamoDBAccess",
|
|
114
|
-
* "Effect": "Allow",
|
|
115
|
-
* "Action": [
|
|
116
|
-
* "dynamodb:BatchGetItem",
|
|
117
|
-
* "dynamodb:BatchWriteItem",
|
|
118
|
-
* "dynamodb:Describe*",
|
|
119
|
-
* "dynamodb:List*",
|
|
120
|
-
* "dynamodb:PutItem",
|
|
121
|
-
* "dynamodb:DeleteItem",
|
|
122
|
-
* "dynamodb:GetItem",
|
|
123
|
-
* "dynamodb:Scan",
|
|
124
|
-
* "dynamodb:Query",
|
|
125
|
-
* "dynamodb:UpdateItem"
|
|
126
|
-
* ],
|
|
127
|
-
* "Resource": [
|
|
128
|
-
* "arn:aws:dynamodb:{region}:{account_id}:table/{table_name}",
|
|
129
|
-
* "arn:aws:dynamodb:{region}:{account_id}:table/{table_name}/index/GSI1"
|
|
130
|
-
* ]
|
|
131
|
-
* }
|
|
132
|
-
* ]
|
|
133
|
-
* }
|
|
134
|
-
* ```
|
|
135
|
-
*
|
|
136
|
-
* ## Advanced usage
|
|
137
|
-
*
|
|
138
|
-
* ### Default schema
|
|
139
|
-
*
|
|
140
|
-
* The table respects the single table design pattern. This has many advantages:
|
|
141
|
-
*
|
|
142
|
-
* - Only one table to manage, monitor and provision.
|
|
143
|
-
* - Querying relations is faster than with multi-table schemas (for eg. retrieving all sessions for a user).
|
|
144
|
-
* - Only one table needs to be replicated if you want to go multi-region.
|
|
145
|
-
*
|
|
146
|
-
* > This schema is adapted for use in DynamoDB and based upon our main [schema](https://authjs.dev/reference/core/adapters#models)
|
|
147
|
-
*
|
|
148
|
-
* 
|
|
149
|
-
*
|
|
150
|
-
* You can create this table with infrastructure as code using [`aws-cdk`](https://github.com/aws/aws-cdk) with the following table definition:
|
|
151
|
-
*
|
|
152
|
-
* ```js title="stack.ts"
|
|
153
|
-
* new dynamodb.Table(this, `NextAuthTable`, {
|
|
154
|
-
* tableName: "next-auth",
|
|
155
|
-
* partitionKey: { name: "pk", type: dynamodb.AttributeType.STRING },
|
|
156
|
-
* sortKey: { name: "sk", type: dynamodb.AttributeType.STRING },
|
|
157
|
-
* timeToLiveAttribute: "expires",
|
|
158
|
-
* }).addGlobalSecondaryIndex({
|
|
159
|
-
* indexName: "GSI1",
|
|
160
|
-
* partitionKey: { name: "GSI1PK", type: dynamodb.AttributeType.STRING },
|
|
161
|
-
* sortKey: { name: "GSI1SK", type: dynamodb.AttributeType.STRING },
|
|
162
|
-
* })
|
|
163
|
-
* ```
|
|
164
|
-
*
|
|
165
|
-
* Alternatively, you can use this cloudformation template:
|
|
166
|
-
*
|
|
167
|
-
* ```yaml title=cloudformation.yaml
|
|
168
|
-
* NextAuthTable:
|
|
169
|
-
* Type: "AWS::DynamoDB::Table"
|
|
170
|
-
* Properties:
|
|
171
|
-
* TableName: next-auth
|
|
172
|
-
* AttributeDefinitions:
|
|
173
|
-
* - AttributeName: pk
|
|
174
|
-
* AttributeType: S
|
|
175
|
-
* - AttributeName: sk
|
|
176
|
-
* AttributeType: S
|
|
177
|
-
* - AttributeName: GSI1PK
|
|
178
|
-
* AttributeType: S
|
|
179
|
-
* - AttributeName: GSI1SK
|
|
180
|
-
* AttributeType: S
|
|
181
|
-
* KeySchema:
|
|
182
|
-
* - AttributeName: pk
|
|
183
|
-
* KeyType: HASH
|
|
184
|
-
* - AttributeName: sk
|
|
185
|
-
* KeyType: RANGE
|
|
186
|
-
* GlobalSecondaryIndexes:
|
|
187
|
-
* - IndexName: GSI1
|
|
188
|
-
* Projection:
|
|
189
|
-
* ProjectionType: ALL
|
|
190
|
-
* KeySchema:
|
|
191
|
-
* - AttributeName: GSI1PK
|
|
192
|
-
* KeyType: HASH
|
|
193
|
-
* - AttributeName: GSI1SK
|
|
194
|
-
* KeyType: RANGE
|
|
195
|
-
* TimeToLiveSpecification:
|
|
196
|
-
* AttributeName: expires
|
|
197
|
-
* Enabled: true
|
|
198
|
-
* ```
|
|
199
|
-
*
|
|
200
|
-
* ### Using a custom schema
|
|
201
|
-
*
|
|
202
|
-
* You can configure your custom table schema by passing the `options` key to the adapter constructor:
|
|
203
|
-
*
|
|
204
|
-
* ```js
|
|
205
|
-
* const adapter = DynamoDBAdapter(client, {
|
|
206
|
-
* tableName: "custom-table-name",
|
|
207
|
-
* partitionKey: "custom-pk",
|
|
208
|
-
* sortKey: "custom-sk",
|
|
209
|
-
* indexName: "custom-index-name",
|
|
210
|
-
* indexPartitionKey: "custom-index-pk",
|
|
211
|
-
* indexSortKey: "custom-index-sk",
|
|
212
|
-
* })
|
|
213
|
-
* ```
|
|
214
|
-
**/
|
|
215
40
|
export function DynamoDBAdapter(
|
|
216
41
|
client: DynamoDBDocument,
|
|
217
42
|
options?: DynamoDBAdapterOptions
|
|
@@ -520,15 +345,8 @@ export function DynamoDBAdapter(
|
|
|
520
345
|
}
|
|
521
346
|
}
|
|
522
347
|
|
|
523
|
-
// https://github.com/honeinc/is-iso-date/blob/master/index.js
|
|
524
|
-
const isoDateRE =
|
|
525
|
-
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/
|
|
526
|
-
function isDate(value: any) {
|
|
527
|
-
return value && isoDateRE.test(value) && !isNaN(Date.parse(value))
|
|
528
|
-
}
|
|
529
|
-
|
|
530
348
|
const format = {
|
|
531
|
-
/** Takes a plain old JavaScript object and turns it into a
|
|
349
|
+
/** Takes a plain old JavaScript object and turns it into a DynamoDB object */
|
|
532
350
|
to(object: Record<string, any>) {
|
|
533
351
|
const newObject: Record<string, unknown> = {}
|
|
534
352
|
for (const key in object) {
|