customer-registration 0.0.111 → 0.0.113

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.
Files changed (50) hide show
  1. package/.medusa/server/src/admin/index.js +3249 -2
  2. package/.medusa/server/src/admin/index.mjs +3232 -2
  3. package/.medusa/server/src/api/admin/account-deletion-requests/route.js +30 -0
  4. package/.medusa/server/src/api/admin/account-deletion-requests/validators.js +12 -0
  5. package/.medusa/server/src/api/auth/customer/emailpass/reset-password/route.js +1 -26
  6. package/.medusa/server/src/api/auth/customer/emailpass/route.js +24 -97
  7. package/.medusa/server/src/api/auth/customer/phonepass/register/route.js +50 -0
  8. package/.medusa/server/src/api/auth/customer/phonepass/route.js +105 -0
  9. package/.medusa/server/src/api/middlewares/guard-account-deletion.js +29 -0
  10. package/.medusa/server/src/api/middlewares/ip-rate-limit.js +48 -0
  11. package/.medusa/server/src/api/middlewares/validate-customer-registration.js +60 -0
  12. package/.medusa/server/src/api/middlewares.js +30 -0
  13. package/.medusa/server/src/api/store/customers/account-deletion/cancel-confirm/route.js +36 -0
  14. package/.medusa/server/src/api/store/customers/account-deletion/cancel-request/route.js +55 -0
  15. package/.medusa/server/src/api/store/customers/account-deletion/confirm/route.js +43 -0
  16. package/.medusa/server/src/api/store/customers/account-deletion/request/route.js +40 -0
  17. package/.medusa/server/src/api/store/customers/account-deletion/validators.js +27 -0
  18. package/.medusa/server/src/api/store/customers/me/contact/route.js +95 -0
  19. package/.medusa/server/src/api/store/customers/me/contact/verify/route.js +83 -0
  20. package/.medusa/server/src/api/store/customers/me/route.js +53 -0
  21. package/.medusa/server/src/api/store/customers/otp/send/route.js +1 -6
  22. package/.medusa/server/src/api/store/customers/otp/verify/route.js +95 -3
  23. package/.medusa/server/src/api/store/customers/route.js +89 -0
  24. package/.medusa/server/src/config.js +44 -13
  25. package/.medusa/server/src/jobs/process-account-deletions.js +69 -0
  26. package/.medusa/server/src/modules/account-deletion-request/index.js +17 -0
  27. package/.medusa/server/src/modules/account-deletion-request/migrations/Migration20250221000000CreateAccountDeletionRequestTable.js +42 -0
  28. package/.medusa/server/src/modules/account-deletion-request/migrations/Migration20250221100000AddCompletedStatusToAccountDeletionRequest.js +30 -0
  29. package/.medusa/server/src/modules/account-deletion-request/models/account-deletion-request.js +26 -0
  30. package/.medusa/server/src/modules/account-deletion-request/service.js +90 -0
  31. package/.medusa/server/src/modules/otp-verification/migrations/Migration20250221000000AddAccountDeletionOtpPurposes.js +35 -0
  32. package/.medusa/server/src/modules/otp-verification/models/otp-verification.js +9 -2
  33. package/.medusa/server/src/modules/otp-verification/service.js +79 -1
  34. package/.medusa/server/src/providers/phonepass/index.js +9 -0
  35. package/.medusa/server/src/providers/phonepass/service.js +133 -0
  36. package/.medusa/server/src/subscribers/password-reset.js +1 -42
  37. package/.medusa/server/src/workflows/change-password.js +40 -64
  38. package/.medusa/server/src/workflows/send-contact-change-otp-workflow.js +41 -0
  39. package/.medusa/server/src/workflows/steps/determine-contact-method-step.js +8 -2
  40. package/.medusa/server/src/workflows/steps/generate-contact-change-otp-step.js +24 -0
  41. package/.medusa/server/src/workflows/steps/index.js +6 -2
  42. package/.medusa/server/src/workflows/steps/resolve-channel-config-step.js +10 -1
  43. package/.medusa/server/src/workflows/steps/send-notification-step.js +1 -11
  44. package/.medusa/server/src/workflows/steps/sync-phonepass-entity-id-step.js +63 -0
  45. package/.medusa/server/src/workflows/steps/update-password-step.js +21 -29
  46. package/.medusa/server/src/workflows/update-contact-workflow.js +100 -0
  47. package/.medusa/server/src/workflows/verify-phone.js +11 -4
  48. package/README.md +389 -147
  49. package/package.json +12 -3
  50. package/.medusa/server/src/subscribers/customer-updated.js +0 -100
package/README.md CHANGED
@@ -1,18 +1,20 @@
1
1
  # Medusa Plugin: Customer Registration & OTP Verification
2
2
 
3
- A comprehensive Medusa v2 plugin that provides OTP-based verification for email and phone functionality, with support for Medusa's built-in password reset flow.
3
+ A comprehensive Medusa v2 plugin that provides OTP-based verification for email and phone functionality, with support for flexible registration identifiers, phone-only authentication, contact change flows, and account deletion.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Unified OTP API**: Single endpoints for sending and verifying OTPs
8
- - **Token-based Verification**: Secure JWT token system for OTP verification
9
- - **Multiple Verification Types**: Email verification and phone verification
10
- - **Workflow-based Processing**: Automatic handling of verification flags
11
- - **Password Reset Support**: Notification subscriber for Medusa's built-in password reset flow
12
- - **Flexible Configuration**: Per-purpose channel configuration (email/SMS)
13
- - **Automatic Contact Detection**: Automatically selects email/phone from customer based on channel
14
- - **Throttling & Rate Limiting**: Built-in protection against abuse
15
- - **Database Migrations**: Automatic schema updates for verification columns
7
+ - **Unified OTP API**: Single endpoints for sending and verifying OTPs
8
+ - **Token-based Verification**: Secure JWT token system for OTP verification
9
+ - **Multiple Verification Types**: Email verification and phone verification
10
+ - **Workflow-based Processing**: Automatic handling of verification flags
11
+ - **Password Reset Support**: Notification subscriber for Medusa's built-in password reset flow
12
+ - **Flexible Configuration**: Per-purpose channel configuration (email/SMS)
13
+ - **Throttling & Rate Limiting**: Built-in protection against OTP spam
14
+ - **Database Migrations**: Automatic schema updates for verification columns
15
+ - **Account Deletion Request Flow**: Two-step OTP flow to request and confirm account deletion with optional cancel flow
16
+ - **Phone-only Authentication**: `phonepass` auth provider for registering and logging in with phone + password (no email required)
17
+ - **Authenticated Contact Change**: Dedicated OTP-verified routes for updating phone or email — new value is embedded in the signed JWT, no metadata staging required
16
18
 
17
19
  ## Quick Start
18
20
 
@@ -30,16 +32,31 @@ export default defineConfig({
30
32
  {
31
33
  resolve: "customer-registration",
32
34
  options: {
33
- // Storefront URL for constructing reset password links
34
- storefrontUrl: "http://localhost:8000", // Optional: base URL for reset links
35
-
36
- // Password reset configuration
35
+ storefrontUrl: "http://localhost:8000",
36
+
37
+ registration: {
38
+ identifier: "phone", // "email" | "phone" | "both"
39
+ require_verification: true,
40
+ },
41
+ login: {
42
+ identifier: "phone", // defaults to registration.identifier
43
+ },
44
+
37
45
  password_reset: {
38
- template: "src/templates/emails/password-reset.html", // Required: path to HTML template
39
- subject: "Reset Your Password", // Optional: email subject
46
+ template: "src/templates/emails/password-reset.html",
47
+ subject: "Reset Your Password",
48
+ },
49
+
50
+ account_deletion_request: {
51
+ template: "src/templates/emails/account-deletion-request.html",
52
+ subject: "Confirm your account deletion request",
53
+ scheduled_days: 7,
40
54
  },
41
-
42
- // OTP channel configuration
55
+ account_deletion_cancel: {
56
+ template: "src/templates/emails/account-deletion-cancel.html",
57
+ subject: "Confirm cancellation of account deletion",
58
+ },
59
+
43
60
  email_verification: {
44
61
  channel: "email",
45
62
  subject: "Verify your email",
@@ -53,33 +70,17 @@ export default defineConfig({
53
70
  })
54
71
  ```
55
72
 
56
- **Required Options:**
57
- - `password_reset.template` - Path to HTML template file for password reset emails
58
-
59
73
  3. **Run migrations**:
60
74
  ```bash
61
75
  npx medusa db:migrate
62
76
  ```
63
77
 
64
- 4. **Use the API**:
65
- ```bash
66
- # Send OTP
67
- POST /store/customers/otp/send
68
- {
69
- "customer_id": "cus_...",
70
- "type": "email_verification"
71
- }
72
-
73
- # Verify OTP
74
- POST /store/customers/otp/verify
75
- {
76
- "token": "...",
77
- "code": "123456"
78
- }
79
- ```
78
+ 4. **Use the API** — see [API Endpoints](#api-endpoints) below.
80
79
 
81
80
  📖 **For complete documentation, see [USAGE.md](./USAGE.md)**
82
81
 
82
+ ---
83
+
83
84
  ## Installation
84
85
 
85
86
  ### Local Development
@@ -96,18 +97,7 @@ cd ../../test-medusa
96
97
  npx medusa plugin:add customer-registration
97
98
  ```
98
99
 
99
- 3. Register the plugin in `medusa-config.ts`:
100
- ```typescript
101
- module.exports = defineConfig({
102
- // ... other config
103
- plugins: [
104
- {
105
- resolve: "customer-registration",
106
- options: {},
107
- },
108
- ],
109
- })
110
- ```
100
+ 3. Register the plugin in `medusa-config.ts` (see Quick Start above).
111
101
 
112
102
  4. Start development mode (in plugin directory):
113
103
  ```bash
@@ -121,137 +111,386 @@ cd ../../test-medusa
121
111
  yarn dev
122
112
  ```
123
113
 
124
- ## Usage
125
-
126
- ### Registration lifecycle hook
127
-
128
- The plugin no longer overrides `POST /store/customers`. Instead, it listens to the `customer.created` event and automatically issues an email OTP (when `email.autoSendOnRegistration` is enabled). Because the default Medusa route still handles persistence and response formatting, there are no behavioral differences for registration requests aside from the verification guard.
114
+ ---
129
115
 
130
- ### API Endpoints
116
+ ## Configuration
131
117
 
132
- The plugin provides unified OTP endpoints:
133
-
134
- | Endpoint | Method | Description |
135
- | --- | --- | --- |
136
- | `/store/customers/otp/send` | POST | Send OTP for email/phone verification |
137
- | `/store/customers/otp/verify` | POST | Verify OTP code and execute appropriate workflow |
118
+ ### `registration.identifier`
138
119
 
139
- **Request Types**:
140
- - `email_verification` - Verify customer email
141
- - `phone_verification` - Verify customer phone
142
- - Note: Password reset uses Medusa's built-in flow (see Password Reset section below)
120
+ Controls which field is required at sign-up:
143
121
 
144
- See [USAGE.md](./USAGE.md) for detailed API documentation and examples.
122
+ | Value | Behaviour |
123
+ |---|---|
124
+ | `"email"` (default) | Email required; standard Medusa registration |
125
+ | `"phone"` | Phone required; no email needed; uses `phonepass` provider |
126
+ | `"both"` | Both email and phone required |
145
127
 
146
- ### Example Flow
128
+ ### `login.identifier`
147
129
 
148
- 1. **Register Customer** - Use standard Medusa customer registration endpoint
149
- 2. **Send OTP** - Request OTP using unified endpoint with type
150
- 3. **Verify OTP** - Verify code using token from send response
151
- 4. **Login** - Customer can login after email verification
130
+ Controls which auth providers are accepted at login. Defaults to `registration.identifier`.
152
131
 
153
- See [USAGE.md](./USAGE.md) for complete examples and integration guide.
132
+ | Value | Accepted login methods |
133
+ |---|---|
134
+ | `"email"` | `POST /auth/customer/emailpass` only |
135
+ | `"phone"` | `POST /auth/customer/phonepass` only |
136
+ | `"both"` | Both emailpass and phonepass accepted |
154
137
 
155
- ### Configuration
156
-
157
- The plugin uses purpose-based configuration:
138
+ ### Full options reference
158
139
 
159
140
  ```typescript
160
141
  {
161
142
  resolve: "customer-registration",
162
143
  options: {
163
- otpLength: 6,
164
- otpCharset: "numeric",
165
- otpExpiryMinutes: 15,
166
- maxAttempts: 5,
167
- email_verification: {
168
- channel: "email",
169
- template: "otp-email-verify",
170
- subject: "Verify your email",
171
- resendThrottleSeconds: 90,
144
+ storefrontUrl?: string, // Base URL for password reset links
145
+
146
+ registration?: {
147
+ identifier?: "email" | "phone" | "both", // default: "email"
148
+ require_verification?: boolean, // default: true
149
+ },
150
+ login?: {
151
+ identifier?: "email" | "phone" | "both", // default: registration.identifier
152
+ },
153
+
154
+ // OTP settings (apply to all types)
155
+ otpLength?: number, // default: 6
156
+ otpCharset?: "numeric" | "alphanumeric", // default: "numeric"
157
+ otpExpiryMinutes?: number, // default: 15
158
+ maxAttempts?: number, // default: 5
159
+
160
+ email_verification?: {
161
+ channel: string, // e.g. "email"
162
+ template?: string,
163
+ subject?: string,
164
+ resendThrottleSeconds?: number,
165
+ autoSendOnRegistration?: boolean,
172
166
  },
173
- phone_verification: {
174
- channel: "sms",
175
- template: "otp-phone-verify",
176
- resendThrottleSeconds: 60,
167
+ phone_verification?: {
168
+ channel: string, // e.g. "sms"
169
+ template?: string,
170
+ resendThrottleSeconds?: number,
171
+ },
172
+
173
+ password_reset?: {
174
+ template: string, // Required when using password reset
175
+ subject?: string,
176
+ },
177
+ account_deletion_request?: {
178
+ template: string,
179
+ subject?: string,
180
+ scheduled_days?: number, // default: 7
181
+ },
182
+ account_deletion_cancel?: {
183
+ template: string,
184
+ subject?: string,
177
185
  },
178
186
  },
179
187
  }
180
188
  ```
181
189
 
182
- See [USAGE.md](./USAGE.md) for complete configuration reference.
190
+ ---
183
191
 
184
- ### Database Migrations
192
+ ## API Endpoints
185
193
 
186
- The plugin includes two migrations:
194
+ ### Registration & Initial Verification
187
195
 
188
- 1. **Migration20250120000000AddCustomerVerificationColumns**
189
- - Adds `email_verified` and `phone_verified` columns to customer table
190
- - Creates indexes for performance
196
+ | Endpoint | Method | Auth | Description |
197
+ |---|---|---|---|
198
+ | `/store/customers` | POST | Bearer (pre-customer) | Create customer account |
199
+ | `/store/customers/otp/send` | POST | — | Send OTP for initial email/phone verification |
200
+ | `/store/customers/otp/verify` | POST | — | Verify OTP code; returns login token on success |
191
201
 
192
- 2. **Migration20250118001000CreateOtpVerificationTable**
193
- - Creates `otp_verification` table for storing OTP records
202
+ #### Send OTP
194
203
 
195
- Run migrations after installation:
196
204
  ```bash
197
- npx medusa db:migrate
205
+ POST /store/customers/otp/send
206
+ {
207
+ "customer_id": "cus_...",
208
+ "type": "phone_verification" # or "email_verification"
209
+ }
210
+ # Response: { "token": "...", "expires_at": "..." }
198
211
  ```
199
212
 
200
- ## Requirements
213
+ #### Verify OTP
201
214
 
202
- - Medusa v2.11.2 or higher
203
- - Node.js >= 20
204
- - Notification module configured with at least one provider (email/SMS)
205
- - Database migrations applied (`npx medusa db:migrate`)
215
+ ```bash
216
+ POST /store/customers/otp/verify
217
+ {
218
+ "token": "<token from send>",
219
+ "code": "482917"
220
+ }
221
+ # Response: { "verified": true, "customer": {...}, "token": "<login jwt>", "needs_login": false }
222
+ ```
206
223
 
207
- ## Documentation
224
+ ---
208
225
 
209
- - **[USAGE.md](./USAGE.md)** - Complete usage guide with examples
210
- - **[README.md](./README.md)** - This file (overview and quick start)
226
+ ### Login
211
227
 
212
- ## Modules
228
+ | Endpoint | Method | Description |
229
+ |---|---|---|
230
+ | `/auth/customer/emailpass` | POST | Login with email + password |
231
+ | `/auth/customer/phonepass` | POST | Login with phone + password |
232
+ | `/auth/customer/emailpass/register` | POST | Create emailpass auth identity |
233
+ | `/auth/customer/phonepass/register` | POST | Create phonepass auth identity |
213
234
 
214
- The plugin includes two modules:
235
+ ---
215
236
 
216
- 1. **`otp-verification`** - OTP generation, verification, and management
217
- 2. **`customer-registration`** - Customer registration logic and overrides
237
+ ### Contact Change (Phone or Email Update)
218
238
 
219
- ## Workflows
239
+ > These are the dedicated authenticated routes for changing a customer's phone or email.
240
+ > `PATCH /store/customers/me` **rejects** `phone` and `email` fields — all contact changes must go through these endpoints.
220
241
 
221
- The plugin uses workflows for different verification types:
242
+ | Endpoint | Method | Auth | Description |
243
+ |---|---|---|---|
244
+ | `/store/customers/me/contact` | POST | Customer JWT | Request contact change — validates new value, sends OTP, returns token |
245
+ | `/store/customers/me/contact/verify` | POST | Customer JWT | Verify OTP and apply the change |
222
246
 
223
- - `verify-email` - Sets email_verified flag
224
- - `verify-phone` - Sets phone_verified flag
247
+ #### How it works
225
248
 
226
- ## Password Reset
249
+ The new phone or email is embedded directly in the signed OTP JWT. No metadata is written to the customer record during the pending state. On successful verification:
227
250
 
228
- This plugin provides password reset functionality using Medusa's AUTH module:
251
+ 1. `customer.phone` / `customer.email` is updated
252
+ 2. `phone_verified` / `email_verified` is set to `true`
253
+ 3. `provider_identity.entity_id` is updated for `phonepass` / `emailpass` **only when the changed field is the active `login.identifier`** — so login continues to work with the new value
229
254
 
230
- 1. **Request Reset**: POST to `/auth/customer/emailpass/reset-password` with email (or `identifier`)
231
- - Custom route that generates JWT reset token using Medusa's `generateJwtTokenForAuthIdentity`
232
- - Sends password reset email directly via notification service
233
- - Returns 201 status (matches Medusa's built-in route behavior)
234
- 2. **Email Sent**: Password reset email is sent with reset token and URL
235
- 3. **Complete Reset**: POST to `/auth/customer/emailpass/update` with token and new password
236
- - Uses AUTH module's `authenticate()` method with `update-password` action
237
- - AUTH module validates token and updates password
255
+ #### Step 1 Request the change
238
256
 
239
- **Key Features:**
240
- - Uses Medusa's AUTH module for token generation and password updates
241
- - Custom routes that match Medusa's built-in route behavior
242
- - Email sending handled directly in the route (subscriber available for `auth.password_reset` event)
243
- - Consistent with Medusa's authentication patterns
257
+ ```bash
258
+ curl -X POST http://localhost:9000/store/customers/me/contact \
259
+ -H "Content-Type: application/json" \
260
+ -H "Authorization: Bearer $CUSTOMER_JWT" \
261
+ -d '{ "phone": "+15559998888" }'
244
262
 
245
- **Note:** These custom routes override Medusa's built-in routes at the same paths. The subscriber listens to `auth.password_reset` event (emitted by Medusa's built-in route) but since we're using custom routes, emails are sent directly from the route.
263
+ # Response
264
+ { "token": "<otp_token>", "expires_at": "2026-03-12T10:15:00.000Z" }
265
+ ```
246
266
 
247
- **Configuration Required:**
248
- - Set `password_reset.template` in plugin options (path to HTML template file)
249
- - Configure email template with ID `password-reset` in your notification provider (optional, subscriber includes HTML)
250
- - Ensure AUTH module is configured with `emailpass` provider
267
+ Only one field at a time is accepted. Sending both `phone` and `email` returns a `400`.
251
268
 
252
- **Helper Functions:**
269
+ #### Step 2 — Verify the OTP
253
270
 
254
- The plugin provides helper functions for password reset operations:
271
+ ```bash
272
+ curl -X POST http://localhost:9000/store/customers/me/contact/verify \
273
+ -H "Content-Type: application/json" \
274
+ -H "Authorization: Bearer $CUSTOMER_JWT" \
275
+ -d '{
276
+ "token": "<otp_token from step 1>",
277
+ "code": "482917"
278
+ }'
279
+
280
+ # Response
281
+ {
282
+ "customer": { "id": "cus_...", "phone": "+15559998888", ... },
283
+ "token": "<fresh_login_jwt>"
284
+ }
285
+ ```
286
+
287
+ The response includes a **fresh login JWT** so the caller is immediately re-authenticated after the change.
288
+
289
+ #### Security notes
290
+
291
+ - The OTP token is signed with the server's `jwtSecret` — the new value cannot be tampered with
292
+ - The verify route checks that `token.customer_id === auth_context.actor_id`, preventing one customer from applying another's OTP
293
+ - `provider_identity.entity_id` sync has a compensation function: if a later workflow step fails the `entity_id` is rolled back to the original value
294
+ - If the current phone/email is `null` (first-time contact assignment), the flow works identically — the field is set from null to the new value and marked verified
295
+
296
+ #### What `PATCH /store/customers/me` does now
297
+
298
+ Non-contact fields (e.g. `first_name`, `last_name`) continue to work as before. Passing `phone` or `email` in the body returns:
299
+
300
+ ```json
301
+ {
302
+ "type": "not_allowed",
303
+ "message": "Phone changes require OTP verification. Use POST /store/customers/me/contact to request a change."
304
+ }
305
+ ```
306
+
307
+ ---
308
+
309
+ ### Profile Update
310
+
311
+ | Endpoint | Method | Auth | Description |
312
+ |---|---|---|---|
313
+ | `/store/customers/me` | PATCH | Customer JWT | Update non-contact profile fields (first_name, last_name, etc.) |
314
+
315
+ ---
316
+
317
+ ### Password Reset
318
+
319
+ | Endpoint | Method | Description |
320
+ |---|---|---|
321
+ | `/auth/customer/emailpass/reset-password` | POST | Request password reset email |
322
+ | `/auth/customer/emailpass/update` | POST | Complete password reset with token |
323
+
324
+ ```bash
325
+ # Request reset
326
+ POST /auth/customer/emailpass/reset-password
327
+ { "identifier": "customer@example.com" }
328
+
329
+ # Complete reset
330
+ POST /auth/customer/emailpass/update
331
+ { "token": "<reset_token>", "password": "NewPassword123!" }
332
+ ```
333
+
334
+ ---
335
+
336
+ ### Account Deletion
337
+
338
+ | Endpoint | Method | Auth | Description |
339
+ |---|---|---|---|
340
+ | `/store/customers/account-deletion/request` | POST | Customer JWT | Request deletion — sends OTP, returns token |
341
+ | `/store/customers/account-deletion/confirm` | POST | — | Confirm deletion with OTP code |
342
+ | `/store/customers/account-deletion/cancel-request` | POST | — | Request cancellation (lookup by email/phone) |
343
+ | `/store/customers/account-deletion/cancel-confirm` | POST | — | Confirm cancellation with OTP code |
344
+ | `/admin/account-deletion-requests` | GET | Admin JWT | List deletion requests |
345
+
346
+ ```bash
347
+ # 1. Request deletion
348
+ curl -X POST http://localhost:9000/store/customers/account-deletion/request \
349
+ -H "Authorization: Bearer $CUSTOMER_JWT" \
350
+ -d '{"reason": "No longer need account"}'
351
+ # Response: { "token": "...", "expires_at": "..." }
352
+
353
+ # 2. Confirm deletion
354
+ curl -X POST http://localhost:9000/store/customers/account-deletion/confirm \
355
+ -d '{"token": "...", "code": "123456"}'
356
+
357
+ # 3. Request cancel (no auth; email lookup)
358
+ curl -X POST http://localhost:9000/store/customers/account-deletion/cancel-request \
359
+ -d '{"email": "customer@example.com"}'
360
+
361
+ # 4. Confirm cancel
362
+ curl -X POST http://localhost:9000/store/customers/account-deletion/cancel-confirm \
363
+ -d '{"token": "...", "code": "123456"}'
364
+ ```
365
+
366
+ ---
367
+
368
+ ## Phone-only Registration & Login (`phonepass`)
369
+
370
+ When `registration.identifier = "phone"`, customers register and log in with phone + password only. No email address is required.
371
+
372
+ ### 1. Register the provider in `medusa-config.ts`
373
+
374
+ ```typescript
375
+ import { Modules } from "@medusajs/framework/utils"
376
+
377
+ export default defineConfig({
378
+ modules: [
379
+ {
380
+ resolve: "@medusajs/medusa/auth",
381
+ options: {
382
+ providers: [
383
+ {
384
+ resolve: "customer-registration/providers/phonepass",
385
+ id: "phonepass",
386
+ },
387
+ ],
388
+ },
389
+ },
390
+ ],
391
+ plugins: [
392
+ {
393
+ resolve: "customer-registration",
394
+ options: {
395
+ registration: {
396
+ identifier: "phone",
397
+ require_verification: true,
398
+ },
399
+ login: {
400
+ identifier: "phone",
401
+ },
402
+ phone_verification: {
403
+ channel: "sms",
404
+ },
405
+ },
406
+ },
407
+ ],
408
+ })
409
+ ```
410
+
411
+ ### 2. Registration flow
412
+
413
+ ```bash
414
+ # Step 1 — create phonepass auth identity
415
+ POST /auth/customer/phonepass/register
416
+ { "phone": "+15551234567", "password": "SecretPass1!" }
417
+ # Response: { "token": "<pre-customer jwt>" }
418
+
419
+ # Step 2 — create customer record
420
+ POST /store/customers
421
+ Authorization: Bearer <token>
422
+ { "phone": "+15551234567", "first_name": "Jane" }
423
+
424
+ # Step 3 — send phone OTP
425
+ POST /store/customers/otp/send
426
+ { "customer_id": "cus_...", "type": "phone_verification" }
427
+ # Response: { "token": "<otp_token>", "expires_at": "..." }
428
+
429
+ # Step 4 — verify phone OTP (returns login token)
430
+ POST /store/customers/otp/verify
431
+ { "token": "<otp_token>", "code": "482917" }
432
+ # Response: { "verified": true, "phone_verified": true, "token": "<login jwt>" }
433
+ ```
434
+
435
+ ### 3. Login flow
436
+
437
+ ```bash
438
+ POST /auth/customer/phonepass
439
+ { "phone": "+15551234567", "password": "SecretPass1!" }
440
+ # Response: { "token": "<jwt>" }
441
+ ```
442
+
443
+ ### 4. Update phone (after registration)
444
+
445
+ ```bash
446
+ # Request change
447
+ POST /store/customers/me/contact
448
+ Authorization: Bearer <login jwt>
449
+ { "phone": "+15559998888" }
450
+ # Response: { "token": "<otp_token>", "expires_at": "..." }
451
+
452
+ # Verify and apply
453
+ POST /store/customers/me/contact/verify
454
+ Authorization: Bearer <login jwt>
455
+ { "token": "<otp_token>", "code": "739201" }
456
+ # Response: { "customer": { "phone": "+15559998888", ... }, "token": "<fresh jwt>" }
457
+ ```
458
+
459
+ ---
460
+
461
+ ## Modules
462
+
463
+ The plugin includes three modules:
464
+
465
+ 1. **`otp-verification`** — OTP generation, verification, and management
466
+ 2. **`customer-registration`** — Customer registration logic and route overrides
467
+ 3. **`account-deletion-request`** — Account deletion request lifecycle (pending → confirmed → completed/cancelled)
468
+
469
+ ## Workflows
470
+
471
+ | Workflow | Description |
472
+ |---|---|
473
+ | `verify-email` | Sets `email_verified = true` on the customer record |
474
+ | `verify-phone` | Sets `phone_verified = true` on the customer record |
475
+ | `update-contact` | Updates `customer.phone` / `customer.email`, sets verified flag, syncs `provider_identity.entity_id` when applicable |
476
+ | `send-otp` | Resolves channel config, generates OTP, sends notification |
477
+ | `send-contact-change-otp` | Generates OTP with `new_value` embedded in JWT, sends to the new contact address |
478
+ | `change-password` | Updates customer password via the auth module |
479
+
480
+ ## Database Migrations
481
+
482
+ | Migration | Description |
483
+ |---|---|
484
+ | `Migration20250120000000AddCustomerVerificationColumns` | Adds `email_verified` and `phone_verified` columns to the customer table |
485
+ | `Migration20250118001000CreateOtpVerificationTable` | Creates `otp_verification` table |
486
+ | `Migration20250221000000CreateAccountDeletionRequestTable` | Creates `account_deletion_request` table |
487
+ | `Migration20250221000000AddAccountDeletionOtpPurposes` | Extends `otp_verification.purpose` enum for account deletion flows |
488
+
489
+ ```bash
490
+ npx medusa db:migrate
491
+ ```
492
+
493
+ ## Password Reset (Helper Functions)
255
494
 
256
495
  ```typescript
257
496
  import {
@@ -259,13 +498,11 @@ import {
259
498
  completePasswordReset,
260
499
  } from "customer-registration/helpers"
261
500
 
262
- // Request password reset
263
501
  await requestPasswordReset(
264
502
  { email: "customer@example.com" },
265
503
  { baseUrl: "https://store.example.com", publishableApiKey: "pk_..." }
266
504
  )
267
505
 
268
- // Complete password reset
269
506
  await completePasswordReset(
270
507
  {
271
508
  email: "customer@example.com",
@@ -276,24 +513,29 @@ await completePasswordReset(
276
513
  )
277
514
  ```
278
515
 
279
- See [USAGE.md](./USAGE.md) for complete helper function documentation.
516
+ ## Requirements
280
517
 
281
- ## Development
518
+ - Medusa v2.11.2 or higher
519
+ - Node.js >= 20
520
+ - Notification module configured with at least one provider (email/SMS)
521
+ - Database migrations applied (`npx medusa db:migrate`)
522
+ - `phonepass` provider registered in auth module (required when `registration.identifier` is `"phone"` or `"both"`)
282
523
 
283
- ### Build
524
+ ## Documentation
284
525
 
285
- ```bash
286
- npm run build
287
- ```
526
+ - **[USAGE.md](./USAGE.md)** — Complete usage guide with examples
527
+ - **[README.md](./README.md)** — This file (overview and quick start)
288
528
 
289
- ### Watch for Changes
529
+ ## Development
290
530
 
291
531
  ```bash
532
+ # Build
533
+ npm run build
534
+
535
+ # Watch mode
292
536
  npx medusa plugin:develop
293
537
  ```
294
538
 
295
- This command watches for changes and automatically rebuilds and publishes the plugin to the local registry.
296
-
297
539
  ## License
298
540
 
299
541
  MIT