@orieljs/framework 0.1.0-alpha.5 → 0.1.0-alpha.7
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/NOTICE +7 -0
- package/README.md +10 -1
- package/TRADEMARKS.md +33 -0
- package/dist/{chunk-WNJP46B7.js → chunk-4MWG3B7G.js} +1785 -626
- package/dist/chunk-4MWG3B7G.js.map +1 -0
- package/dist/chunk-7ZQZYDOC.js +3253 -0
- package/dist/chunk-7ZQZYDOC.js.map +1 -0
- package/dist/{chunk-BSQKOLSK.js → chunk-GVNLZZTN.js} +1 -1
- package/dist/chunk-GVNLZZTN.js.map +1 -0
- package/dist/{chunk-A5XRLEWM.js → chunk-VOYW3R5J.js} +4 -4
- package/dist/chunk-VOYW3R5J.js.map +1 -0
- package/dist/contracts.d.ts +535 -17
- package/dist/contracts.js +1 -1
- package/dist/index.d-WQpfdIbG.d.ts +630 -0
- package/dist/index.d.ts +2202 -5952
- package/dist/index.js +4900 -944
- package/dist/index.js.map +1 -1
- package/dist/{jsx-runtime-WKTl3EEw.d.ts → jsx-runtime-6um4Mwfb.d.ts} +97 -51
- package/dist/jsx-runtime.d.ts +2 -2
- package/dist/jsx-runtime.js +3 -3
- package/dist/{testing-BErengYY.d.ts → testing-CKwfWJGn.d.ts} +313 -994
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +19 -5
- package/docs/authentication.md +487 -0
- package/docs/authorization.md +435 -0
- package/docs/cache.md +647 -0
- package/docs/collections.md +2270 -0
- package/docs/configuration.md +334 -0
- package/docs/console.md +651 -0
- package/docs/container.md +430 -0
- package/docs/controllers.md +406 -0
- package/docs/csrf.md +126 -0
- package/docs/database-testing.md +144 -0
- package/docs/database.md +236 -0
- package/docs/deployment.md +276 -0
- package/docs/eloquent-collections.md +218 -0
- package/docs/eloquent-factories.md +255 -0
- package/docs/eloquent-mutators.md +254 -0
- package/docs/eloquent-observers.md +145 -0
- package/docs/eloquent-relationships.md +557 -0
- package/docs/eloquent.md +494 -0
- package/docs/encryption.md +104 -0
- package/docs/errors.md +318 -0
- package/docs/events.md +336 -0
- package/docs/facades.md +278 -0
- package/docs/hashing.md +118 -0
- package/docs/helpers.md +1281 -0
- package/docs/http-tests.md +386 -0
- package/docs/inertia.md +485 -0
- package/docs/installation.md +209 -0
- package/docs/lifecycle.md +234 -0
- package/docs/live-tests.md +226 -0
- package/docs/live.md +910 -0
- package/docs/logging.md +255 -0
- package/docs/mail.md +619 -0
- package/docs/middleware.md +384 -0
- package/docs/migrations.md +416 -0
- package/docs/mocking.md +264 -0
- package/docs/navigation.json +273 -0
- package/docs/notifications.md +225 -0
- package/docs/pagination.md +247 -0
- package/docs/passwords.md +207 -0
- package/docs/providers.md +187 -0
- package/docs/queries.md +600 -0
- package/docs/queues.md +330 -0
- package/docs/requests.md +533 -0
- package/docs/responses.md +444 -0
- package/docs/routing.md +738 -0
- package/docs/scheduling.md +277 -0
- package/docs/seeding.md +122 -0
- package/docs/session.md +409 -0
- package/docs/starter-kits.md +396 -0
- package/docs/storage.md +192 -0
- package/docs/structure.md +264 -0
- package/docs/testing.md +165 -0
- package/docs/time-travel.md +138 -0
- package/docs/validation.md +1792 -0
- package/docs/verification.md +152 -0
- package/docs/views.md +566 -0
- package/docs/vite.md +322 -0
- package/package.json +34 -32
- package/dist/chunk-A5XRLEWM.js.map +0 -1
- package/dist/chunk-BSQKOLSK.js.map +0 -1
- package/dist/chunk-PM5YTG57.js +0 -880
- package/dist/chunk-PM5YTG57.js.map +0 -1
- package/dist/chunk-WNJP46B7.js.map +0 -1
- package/dist/index.d-DOlTeG-8.d.ts +0 -99
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Email verification
|
|
2
|
+
|
|
3
|
+
Ask new users to confirm their email address with a signed link before they reach the parts of your app that need it.
|
|
4
|
+
The starter kits with pages do this already.
|
|
5
|
+
|
|
6
|
+
## Introduction
|
|
7
|
+
|
|
8
|
+
When a user registers, Oriel mails them a link. Opening it, while signed in, marks their address as verified, and the
|
|
9
|
+
`verified` middleware keeps unverified users out of the routes you give it. The kits with pages use it for the
|
|
10
|
+
dashboard (see [Email verification](starter-kits.md#email-verification) in the kits).
|
|
11
|
+
|
|
12
|
+
### Model preparation
|
|
13
|
+
|
|
14
|
+
A model built on `AuthenticatableModel`, as a new app's `User` is, can verify its email:
|
|
15
|
+
|
|
16
|
+
- `hasVerifiedEmail()` tells you whether `email_verified_at` is set;
|
|
17
|
+
- `markEmailAsVerified()` sets it to now and saves the model;
|
|
18
|
+
- `getEmailForVerification()` returns the `email` attribute;
|
|
19
|
+
- `sendEmailVerificationNotification()` mails the user the verification link.
|
|
20
|
+
|
|
21
|
+
> [!NOTE]
|
|
22
|
+
> In Laravel, only a `User` model that implements `MustVerifyEmail` gets the mail and is held back by `verified`, and
|
|
23
|
+
> a new Laravel app's doesn't. In Oriel, every user model built on `AuthenticatableModel` can verify its email, so a
|
|
24
|
+
> new user always gets the mail. Take `verified` off a route to let unverified users in.
|
|
25
|
+
|
|
26
|
+
### Database preparation
|
|
27
|
+
|
|
28
|
+
The `users` table needs an `email_verified_at` column, a nullable timestamp, which a new app's first migration has.
|
|
29
|
+
|
|
30
|
+
## Routing
|
|
31
|
+
|
|
32
|
+
Verification takes three routes, which the Inertia kits define in `routes/auth.ts`, behind the `auth` middleware: the
|
|
33
|
+
notice that asks the user to verify, the link's handler, and a route that sends the link again.
|
|
34
|
+
|
|
35
|
+
### The email verification notice
|
|
36
|
+
|
|
37
|
+
The notice is the page a user sees when `verified` stops them. It is the `verification.notice` route,
|
|
38
|
+
`/verify-email` in the kits:
|
|
39
|
+
|
|
40
|
+
```ts title="routes/auth.ts"
|
|
41
|
+
import { inertia, Route } from '@orieljs/framework'
|
|
42
|
+
|
|
43
|
+
Route.middleware('auth').group(() => {
|
|
44
|
+
Route.get('verify-email', () => inertia('Auth/VerifyEmail')).name('verification.notice')
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The kits' notice sends a user who has verified on to the dashboard, and shows a "Resend verification email" button.
|
|
49
|
+
|
|
50
|
+
### The email verification handler
|
|
51
|
+
|
|
52
|
+
The link in the mail opens the `verification.verify` route, `/verify-email/{id}/{hash}`: the user's id, and the
|
|
53
|
+
SHA-1 of their email address. The link is signed, and works for 60 minutes. Its route checks the signature with the
|
|
54
|
+
`signed` middleware, and `EmailVerificationRequest` checks the `id` and `hash` against the signed-in user:
|
|
55
|
+
|
|
56
|
+
```ts title="routes/auth.ts"
|
|
57
|
+
import { EmailVerificationRequest, redirect, Route } from '@orieljs/framework'
|
|
58
|
+
|
|
59
|
+
Route.get('verify-email/{id}/{hash}', async () => {
|
|
60
|
+
await EmailVerificationRequest.validate()
|
|
61
|
+
await new EmailVerificationRequest().fulfill()
|
|
62
|
+
|
|
63
|
+
return redirect().intended('/dashboard')
|
|
64
|
+
})
|
|
65
|
+
.middleware(['auth', 'signed', 'throttle:6,1'])
|
|
66
|
+
.name('verification.verify')
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`validate()` answers 403 when the link is for another user. `fulfill()` marks the email as verified and dispatches
|
|
70
|
+
the `Verified` event, unless it was verified already. A link opened after it expired, or changed, gets a 403 from
|
|
71
|
+
`signed`. The user must be signed in, so a user who opens the link in another browser signs in first, and is then sent
|
|
72
|
+
back to it.
|
|
73
|
+
|
|
74
|
+
The kits' handler is `VerifyEmailController`, which does the same and redirects to the dashboard with `?verified=1`.
|
|
75
|
+
|
|
76
|
+
### Resending the verification email
|
|
77
|
+
|
|
78
|
+
A user who lost the mail can ask for it again: the kits' `verification.send` route sends it, at most six times a
|
|
79
|
+
minute:
|
|
80
|
+
|
|
81
|
+
```ts title="routes/auth.ts"
|
|
82
|
+
import { back, request, Route } from '@orieljs/framework'
|
|
83
|
+
import type { User } from '../app/Models/User'
|
|
84
|
+
|
|
85
|
+
Route.post('email/verification-notification', async () => {
|
|
86
|
+
const user = (await request().user<User>())!
|
|
87
|
+
|
|
88
|
+
await user.sendEmailVerificationNotification()
|
|
89
|
+
|
|
90
|
+
return back().with('status', 'verification-link-sent')
|
|
91
|
+
})
|
|
92
|
+
.middleware(['auth', 'throttle:6,1'])
|
|
93
|
+
.name('verification.send')
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
In the Live kit, the `VerifyEmail` component's action sends it, with no rate limit of its own.
|
|
97
|
+
|
|
98
|
+
### Protecting routes
|
|
99
|
+
|
|
100
|
+
The `verified` middleware lets only verified users through:
|
|
101
|
+
|
|
102
|
+
```ts title="routes/web.ts"
|
|
103
|
+
import { Route, view } from '@orieljs/framework'
|
|
104
|
+
|
|
105
|
+
Route.get('profile', () => view('profile')).middleware(['auth', 'verified'])
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
An unverified user is redirected to the `verification.notice` route, and to the page they wanted once they have
|
|
109
|
+
verified. A request that wants JSON gets a 403, "Your email address is not verified.", instead. `verified:<route>`
|
|
110
|
+
redirects to another named route, and with no `verification.notice` route the redirect goes to `/email/verify`. A
|
|
111
|
+
guest gets the same redirect, so put `auth` first, as above.
|
|
112
|
+
|
|
113
|
+
## Customization
|
|
114
|
+
|
|
115
|
+
#### Verification email customization
|
|
116
|
+
|
|
117
|
+
The mail is the `VerifyEmail` notification's: "Verify Email Address", a line asking the user to click the button, the
|
|
118
|
+
button, and a closing line. It is sent in the styled template of [mail notifications](notifications.md), with a
|
|
119
|
+
plain-text part. `VerifyEmail.toMailUsing()` builds the mail yourself, in a service provider's `boot()`. Its function
|
|
120
|
+
receives the user and the signed link:
|
|
121
|
+
|
|
122
|
+
```ts title="app/Providers/AppServiceProvider.ts"
|
|
123
|
+
import { MailMessage, ServiceProvider, VerifyEmail } from '@orieljs/framework'
|
|
124
|
+
|
|
125
|
+
export class AppServiceProvider extends ServiceProvider {
|
|
126
|
+
override boot(): void {
|
|
127
|
+
VerifyEmail.toMailUsing((notifiable, url) =>
|
|
128
|
+
new MailMessage()
|
|
129
|
+
.subject('Verify Email Address')
|
|
130
|
+
.line('Click the button below to verify your email address.')
|
|
131
|
+
.action('Verify Email Address', url),
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`VerifyEmail.createUrlUsing()` builds the link instead, for example for a client app on another domain, and
|
|
138
|
+
`sendEmailVerificationUsing()` replaces the whole sending, with a function that receives the user.
|
|
139
|
+
|
|
140
|
+
The link works for `auth.verification.expire` minutes, 60 unless your `config/auth.ts` sets it:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const auth = {
|
|
144
|
+
verification: { expire: 120 },
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Events
|
|
149
|
+
|
|
150
|
+
`Registered`, which the kits dispatch when a user signs up, sends the verification mail: Oriel listens for it with
|
|
151
|
+
`SendEmailVerificationNotification`, which mails a user who hasn't verified. `fulfill()` and the kits' handler
|
|
152
|
+
dispatch `Verified` once an address is verified. Listen for either, as for any [event](events.md).
|