@netlify/identity 0.4.2 → 1.0.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 +25 -19
- package/dist/index.cjs +16 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -33
- package/dist/index.d.ts +51 -33
- package/dist/index.js +16 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,23 +3,24 @@
|
|
|
3
3
|
A lightweight, no-config headless authentication library for projects using Netlify Identity. Works in both browser and server contexts.
|
|
4
4
|
This is NOT the Netlify Identity Widget. This library exports standalone async functions (e.g., import { login, getUser } from '@netlify/identity'). There is no class to instantiate and no .init() call. Just import the functions you need and call them.
|
|
5
5
|
|
|
6
|
-
> **Status:** Beta. The API may change before 1.0.
|
|
7
|
-
|
|
8
6
|
**Prerequisites:**
|
|
9
7
|
|
|
10
|
-
- [Netlify Identity](https://docs.netlify.com/security/secure-access-to-sites/identity/) must be enabled on your Netlify project
|
|
8
|
+
- [Netlify Identity](https://docs.netlify.com/security/secure-access-to-sites/identity/) must be enabled on your Netlify project. This happens automatically when running within a [Netlify Agent Runner](https://docs.netlify.com/agent-runner/overview/)
|
|
11
9
|
- **Server-side** functions (`getUser`, `login`, `admin.*`, etc.) require [Netlify Functions](https://docs.netlify.com/build/functions/get-started/) (modern/v2, with `export default`) or [Edge Functions](https://docs.netlify.com/edge-functions/overview/). [Lambda-compatible functions](https://docs.netlify.com/build/functions/lambda-compatibility/) (v1, with `export { handler }`) are **not supported**
|
|
12
10
|
- For local development, use [`netlify dev`](https://docs.netlify.com/cli/local-development/) so the Identity endpoint is available
|
|
13
11
|
|
|
14
12
|
## How this library relates to other Netlify auth packages
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
| [`netlify-identity-widget`](https://github.com/netlify/netlify-identity-widget) | Pre-built login/signup modal (HTML + CSS) | You want a drop-in UI component with no custom design |
|
|
20
|
-
| [`gotrue-js`](https://github.com/netlify/gotrue-js) | Low-level GoTrue HTTP client (browser only) | You're building your own auth wrapper and need direct API access |
|
|
14
|
+
`@netlify/identity` is the recommended library for all new projects. It works in both browser and server contexts, handles cookie management, and normalizes the user object.
|
|
15
|
+
|
|
16
|
+
You may encounter two older packages in existing code or documentation:
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
| Package | Status | What it was |
|
|
19
|
+
| ------------------------------------------------------------------------------- | -------------------------------- | --------------------------------------------- |
|
|
20
|
+
| [`netlify-identity-widget`](https://github.com/netlify/netlify-identity-widget) | Not recommended for new projects | Pre-built login/signup modal with built-in UI |
|
|
21
|
+
| [`gotrue-js`](https://github.com/netlify/gotrue-js) | Not recommended for new projects | Low-level GoTrue HTTP client (browser only) |
|
|
22
|
+
|
|
23
|
+
If you need a pre-built login UI, the widget still works. For everything else (custom UI, server-side auth, admin operations, framework integration), use `@netlify/identity`.
|
|
23
24
|
|
|
24
25
|
## Table of contents
|
|
25
26
|
|
|
@@ -97,7 +98,7 @@ export default async (req: Request, context: Context) => {
|
|
|
97
98
|
getUser(): Promise<User | null>
|
|
98
99
|
```
|
|
99
100
|
|
|
100
|
-
Returns the current authenticated user, or `null` if not logged in. Returns the best available normalized `User` from the current context.
|
|
101
|
+
Returns the current authenticated user, or `null` if not logged in. Returns the best available normalized `User` from the current context. When the Identity API is reachable, most persisted and profile fields are populated, but state-dependent fields (invite, recovery, email-change) may still be `undefined` if the user is not in that state. When falling back to JWT claims (e.g., Identity API unreachable), only `id`, `email`, `provider`, `name`, `pictureUrl`, `roles`, `userMetadata`, and `appMetadata` are available. Never throws.
|
|
101
102
|
|
|
102
103
|
> **Next.js note:** Calling `getUser()` in a Server Component opts the page into [dynamic rendering](https://nextjs.org/docs/app/building-your-application/rendering/server-components#dynamic-rendering) because it reads cookies. This is expected and correct for authenticated pages. Next.js handles the internal dynamic rendering signal automatically.
|
|
103
104
|
|
|
@@ -173,7 +174,7 @@ oauthLogin(provider: string): never
|
|
|
173
174
|
|
|
174
175
|
Redirects to an OAuth provider. The page navigates away, so this function never returns normally. Browser only.
|
|
175
176
|
|
|
176
|
-
The `provider` argument should be one of the `AuthProvider` values: `'google'`, `'github'`, `'gitlab'`, `'bitbucket'`,
|
|
177
|
+
The `provider` argument should be one of the `AuthProvider` values: `'google'`, `'github'`, `'gitlab'`, `'bitbucket'`, or `'facebook'`.
|
|
177
178
|
|
|
178
179
|
**Throws:** `MissingIdentityError` if Identity is not configured. `AuthError` if called on the server.
|
|
179
180
|
|
|
@@ -361,7 +362,7 @@ Gets a single user by ID.
|
|
|
361
362
|
admin.createUser(params: CreateUserParams): Promise<User>
|
|
362
363
|
```
|
|
363
364
|
|
|
364
|
-
Creates a new user. The user is auto-confirmed. Optional `data` forwards allowed fields (`role`, `
|
|
365
|
+
Creates a new user. The user is auto-confirmed. Optional `data` forwards allowed fields (`role`, `app_metadata`, `user_metadata`) to the request body. Other keys are silently ignored. `data` cannot override `email`, `password`, or `confirm`.
|
|
365
366
|
|
|
366
367
|
**Throws:** `AuthError` if called from a browser, the email already exists, or the operator token is missing.
|
|
367
368
|
|
|
@@ -393,16 +394,22 @@ Deletes a user by ID.
|
|
|
393
394
|
interface User {
|
|
394
395
|
id: string
|
|
395
396
|
email?: string
|
|
396
|
-
|
|
397
|
+
confirmedAt?: string
|
|
397
398
|
createdAt?: string
|
|
398
399
|
updatedAt?: string
|
|
400
|
+
role?: string
|
|
399
401
|
provider?: AuthProvider
|
|
400
402
|
name?: string
|
|
401
403
|
pictureUrl?: string
|
|
402
404
|
roles?: string[]
|
|
403
|
-
|
|
405
|
+
invitedAt?: string
|
|
406
|
+
confirmationSentAt?: string
|
|
407
|
+
recoverySentAt?: string
|
|
408
|
+
pendingEmail?: string
|
|
409
|
+
emailChangeSentAt?: string
|
|
410
|
+
lastSignInAt?: string
|
|
411
|
+
userMetadata?: Record<string, unknown>
|
|
404
412
|
appMetadata?: Record<string, unknown>
|
|
405
|
-
rawGoTrueData?: Record<string, unknown>
|
|
406
413
|
}
|
|
407
414
|
```
|
|
408
415
|
|
|
@@ -428,7 +435,7 @@ interface IdentityConfig {
|
|
|
428
435
|
#### `AuthProvider`
|
|
429
436
|
|
|
430
437
|
```ts
|
|
431
|
-
type AuthProvider = 'google' | 'github' | 'gitlab' | 'bitbucket' | 'facebook' | '
|
|
438
|
+
type AuthProvider = 'google' | 'github' | 'gitlab' | 'bitbucket' | 'facebook' | 'email'
|
|
432
439
|
```
|
|
433
440
|
|
|
434
441
|
#### `UserUpdates`
|
|
@@ -451,14 +458,13 @@ interface AdminUserUpdates {
|
|
|
451
458
|
email?: string
|
|
452
459
|
password?: string
|
|
453
460
|
role?: string
|
|
454
|
-
aud?: string
|
|
455
461
|
confirm?: boolean
|
|
456
462
|
app_metadata?: Record<string, unknown>
|
|
457
463
|
user_metadata?: Record<string, unknown>
|
|
458
464
|
}
|
|
459
465
|
```
|
|
460
466
|
|
|
461
|
-
Fields accepted by `admin.updateUser()`. Unlike `UserUpdates`, admin updates can set `role`,
|
|
467
|
+
Fields accepted by `admin.updateUser()`. Unlike `UserUpdates`, admin updates can set `role`, force-confirm a user, and write to `app_metadata`. Only these typed fields are forwarded.
|
|
462
468
|
|
|
463
469
|
#### `SignupData`
|
|
464
470
|
|
|
@@ -499,7 +505,7 @@ interface CreateUserParams {
|
|
|
499
505
|
}
|
|
500
506
|
```
|
|
501
507
|
|
|
502
|
-
Parameters for `admin.createUser()`. Optional `data` forwards allowed fields (`role`, `
|
|
508
|
+
Parameters for `admin.createUser()`. Optional `data` forwards allowed fields (`role`, `app_metadata`, `user_metadata`) to the request body. Other keys are silently ignored.
|
|
503
509
|
|
|
504
510
|
#### `Admin`
|
|
505
511
|
|
package/dist/index.cjs
CHANGED
|
@@ -56,7 +56,7 @@ __export(index_exports, {
|
|
|
56
56
|
module.exports = __toCommonJS(index_exports);
|
|
57
57
|
|
|
58
58
|
// src/types.ts
|
|
59
|
-
var AUTH_PROVIDERS = ["google", "github", "gitlab", "bitbucket", "facebook", "
|
|
59
|
+
var AUTH_PROVIDERS = ["google", "github", "gitlab", "bitbucket", "facebook", "email"];
|
|
60
60
|
|
|
61
61
|
// src/environment.ts
|
|
62
62
|
var import_gotrue_js = __toESM(require("gotrue-js"), 1);
|
|
@@ -681,6 +681,7 @@ var hydrateSession = async () => {
|
|
|
681
681
|
|
|
682
682
|
// src/user.ts
|
|
683
683
|
var toAuthProvider = (value) => typeof value === "string" && AUTH_PROVIDERS.includes(value) ? value : void 0;
|
|
684
|
+
var toOptionalString = (value) => typeof value === "string" && value !== "" ? value : void 0;
|
|
684
685
|
var toRoles = (appMeta) => {
|
|
685
686
|
const roles = appMeta.roles;
|
|
686
687
|
if (Array.isArray(roles) && roles.every((r) => typeof r === "string")) {
|
|
@@ -693,20 +694,25 @@ var toUser = (userData) => {
|
|
|
693
694
|
const appMeta = userData.app_metadata ?? {};
|
|
694
695
|
const name = userMeta.full_name || userMeta.name;
|
|
695
696
|
const pictureUrl = userMeta.avatar_url;
|
|
696
|
-
const { token: _token, ...safeUserData } = userData;
|
|
697
697
|
return {
|
|
698
698
|
id: userData.id,
|
|
699
699
|
email: userData.email,
|
|
700
|
-
|
|
700
|
+
confirmedAt: toOptionalString(userData.confirmed_at),
|
|
701
701
|
createdAt: userData.created_at,
|
|
702
702
|
updatedAt: userData.updated_at,
|
|
703
|
+
role: toOptionalString(userData.role),
|
|
703
704
|
provider: toAuthProvider(appMeta.provider),
|
|
704
705
|
name: typeof name === "string" ? name : void 0,
|
|
705
706
|
pictureUrl: typeof pictureUrl === "string" ? pictureUrl : void 0,
|
|
706
707
|
roles: toRoles(appMeta),
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
708
|
+
invitedAt: toOptionalString(userData.invited_at),
|
|
709
|
+
confirmationSentAt: toOptionalString(userData.confirmation_sent_at),
|
|
710
|
+
recoverySentAt: toOptionalString(userData.recovery_sent_at),
|
|
711
|
+
pendingEmail: toOptionalString(userData.new_email),
|
|
712
|
+
emailChangeSentAt: toOptionalString(userData.email_change_sent_at),
|
|
713
|
+
lastSignInAt: toOptionalString(userData.last_sign_in_at),
|
|
714
|
+
userMetadata: userMeta,
|
|
715
|
+
appMetadata: appMeta
|
|
710
716
|
};
|
|
711
717
|
};
|
|
712
718
|
var claimsToUser = (claims) => {
|
|
@@ -721,7 +727,7 @@ var claimsToUser = (claims) => {
|
|
|
721
727
|
name: typeof name === "string" ? name : void 0,
|
|
722
728
|
pictureUrl: typeof pictureUrl === "string" ? pictureUrl : void 0,
|
|
723
729
|
roles: toRoles(appMeta),
|
|
724
|
-
|
|
730
|
+
userMetadata: userMeta,
|
|
725
731
|
appMetadata: appMeta
|
|
726
732
|
};
|
|
727
733
|
};
|
|
@@ -818,8 +824,7 @@ var getSettings = async () => {
|
|
|
818
824
|
gitlab: external.gitlab ?? false,
|
|
819
825
|
bitbucket: external.bitbucket ?? false,
|
|
820
826
|
facebook: external.facebook ?? false,
|
|
821
|
-
email: external.email ?? false
|
|
822
|
-
saml: external.saml ?? false
|
|
827
|
+
email: external.email ?? false
|
|
823
828
|
}
|
|
824
829
|
};
|
|
825
830
|
} catch (err) {
|
|
@@ -996,7 +1001,7 @@ var createUser = async (params) => {
|
|
|
996
1001
|
confirm: true
|
|
997
1002
|
};
|
|
998
1003
|
if (params.data) {
|
|
999
|
-
const allowedKeys = ["role", "
|
|
1004
|
+
const allowedKeys = ["role", "app_metadata", "user_metadata"];
|
|
1000
1005
|
for (const key of allowedKeys) {
|
|
1001
1006
|
if (key in params.data) {
|
|
1002
1007
|
body[key] = params.data[key];
|
|
@@ -1014,7 +1019,7 @@ var updateUser2 = async (userId, attributes) => {
|
|
|
1014
1019
|
assertServer();
|
|
1015
1020
|
const sanitizedUserId = sanitizeUserId(userId);
|
|
1016
1021
|
const body = {};
|
|
1017
|
-
const allowedKeys = ["email", "password", "role", "
|
|
1022
|
+
const allowedKeys = ["email", "password", "role", "confirm", "app_metadata", "user_metadata"];
|
|
1018
1023
|
for (const key of allowedKeys) {
|
|
1019
1024
|
if (key in attributes) {
|
|
1020
1025
|
body[key] = attributes[key];
|