@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 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
- | Package | What it is | When to use it |
17
- | ------------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------ |
18
- | **`@netlify/identity`** (this library) | Headless TypeScript API for browser and server | You want full control over your auth UI and need server-side auth (SSR, Netlify Functions) |
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
- This library provides a unified API that works in both browser and server contexts, handles cookie management, and normalizes the user object. You do not need to install `gotrue-js` or the widget separately.
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. In the browser or when the server can reach the Identity API, all fields are populated. When falling back to JWT claims (e.g., Identity API unreachable), fields like `createdAt`, `updatedAt`, `emailVerified`, and `rawGoTrueData` may be missing. Never throws.
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'`, `'facebook'`, or `'saml'`.
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`, `aud`, `app_metadata`, `user_metadata`) to the request body. Other keys are silently ignored. `data` cannot override `email`, `password`, or `confirm`.
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
- emailVerified?: boolean
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
- metadata?: Record<string, unknown>
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' | 'saml' | 'email'
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`, `aud`, force-confirm a user, and write to `app_metadata`. Only these typed fields are forwarded.
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`, `aud`, `app_metadata`, `user_metadata`) to the request body. Other keys are silently ignored.
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", "saml", "email"];
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
- emailVerified: !!userData.confirmed_at,
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
- metadata: userMeta,
708
- appMetadata: appMeta,
709
- rawGoTrueData: { ...safeUserData }
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
- metadata: userMeta,
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", "aud", "app_metadata", "user_metadata"];
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", "aud", "confirm", "app_metadata", "user_metadata"];
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];