@netlify/identity 0.1.1-alpha.21 → 0.1.1-alpha.22

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 (2) hide show
  1. package/README.md +41 -15
  2. package/package.json +2 -1
package/README.md CHANGED
@@ -620,32 +620,58 @@ export function load() {
620
620
 
621
621
  ### Handling OAuth callbacks in SPAs
622
622
 
623
- All SPA frameworks need a callback handler that runs on page load to process OAuth redirects, email confirmations, and password recovery tokens.
623
+ All SPA frameworks need a callback handler that runs on page load to process OAuth redirects, email confirmations, and password recovery tokens. Use a **wrapper component** that blocks page content while processing tokens. This prevents a flash of unauthenticated content that occurs when the page renders before the callback completes.
624
624
 
625
625
  ```tsx
626
626
  // React component (works with Next.js, Remix, TanStack Start)
627
- import { useEffect } from 'react'
627
+ import { useEffect, useState } from 'react'
628
628
  import { handleAuthCallback } from '@netlify/identity'
629
629
 
630
- export function CallbackHandler() {
630
+ const AUTH_HASH_PATTERN = /^#(confirmation_token|recovery_token|invite_token|email_change_token|access_token)=/
631
+
632
+ export function CallbackHandler({ children }: { children: React.ReactNode }) {
633
+ const [processing, setProcessing] = useState(
634
+ () => typeof window !== 'undefined' && AUTH_HASH_PATTERN.test(window.location.hash),
635
+ )
636
+ const [error, setError] = useState<string | null>(null)
637
+
631
638
  useEffect(() => {
632
- if (!window.location.hash) return
633
-
634
- handleAuthCallback().then((result) => {
635
- if (!result) return
636
- if (result.type === 'invite') {
637
- window.location.href = `/accept-invite?token=${result.token}`
638
- } else {
639
- window.location.href = '/dashboard'
640
- }
641
- })
639
+ if (!window.location.hash || !AUTH_HASH_PATTERN.test(window.location.hash)) return
640
+
641
+ handleAuthCallback()
642
+ .then((result) => {
643
+ if (!result) {
644
+ setProcessing(false)
645
+ return
646
+ }
647
+ if (result.type === 'invite') {
648
+ window.location.href = `/accept-invite?token=${result.token}`
649
+ } else {
650
+ window.location.href = '/dashboard'
651
+ }
652
+ })
653
+ .catch((err) => {
654
+ setError(err instanceof Error ? err.message : 'Callback failed')
655
+ setProcessing(false)
656
+ })
642
657
  }, [])
643
658
 
644
- return null
659
+ if (error) return <div>Auth error: {error}</div>
660
+ if (processing) return <div>Confirming your account...</div>
661
+ return <>{children}</>
645
662
  }
646
663
  ```
647
664
 
648
- Mount this component in your **root layout** so it runs on every page. If you only mount it on a `/callback` route, OAuth redirects and email confirmation links that land on other pages will not be processed.
665
+ Wrap your page content with this component in your **root layout** so it runs on every page:
666
+
667
+ ```tsx
668
+ // Root layout
669
+ <CallbackHandler>
670
+ <Outlet /> {/* or {children} in Next.js */}
671
+ </CallbackHandler>
672
+ ```
673
+
674
+ If you only mount it on a `/callback` route, OAuth redirects and email confirmation links that land on other pages will not be processed.
649
675
 
650
676
  ## Guides
651
677
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/identity",
3
- "version": "0.1.1-alpha.21",
3
+ "version": "0.1.1-alpha.22",
4
4
  "type": "module",
5
5
  "description": "Add authentication to your Netlify site with a few lines of code",
6
6
  "main": "./dist/index.cjs",
@@ -63,6 +63,7 @@
63
63
  },
64
64
  "author": "Netlify Inc.",
65
65
  "devDependencies": {
66
+ "@types/node": "^25.3.3",
66
67
  "eslint": "^9.0.0",
67
68
  "husky": "^9.1.7",
68
69
  "jsdom": "^28.1.0",