chub-dev 0.1.0 → 0.1.2-beta.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 +55 -0
- package/bin/chub-mcp +2 -0
- package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
- package/dist/airtable/docs/database/python/DOC.md +1735 -0
- package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
- package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
- package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
- package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
- package/dist/asana/docs/tasks/DOC.md +1396 -0
- package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
- package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
- package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
- package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
- package/dist/auth0/docs/identity/python/DOC.md +1199 -0
- package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
- package/dist/aws/docs/s3/python/DOC.md +1807 -0
- package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
- package/dist/binance/docs/trading/python/DOC.md +1454 -0
- package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
- package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
- package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
- package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
- package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
- package/dist/clerk/docs/auth/python/DOC.md +274 -0
- package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
- package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
- package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
- package/dist/cohere/docs/llm/DOC.md +1335 -0
- package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
- package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
- package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
- package/dist/deepgram/docs/speech/python/DOC.md +685 -0
- package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
- package/dist/deepl/docs/translation/python/DOC.md +944 -0
- package/dist/deepseek/docs/llm/DOC.md +1220 -0
- package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
- package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
- package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
- package/dist/discord/docs/bot/python/DOC.md +1130 -0
- package/dist/elasticsearch/docs/search/DOC.md +1634 -0
- package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
- package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
- package/dist/firebase/docs/auth/DOC.md +1015 -0
- package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
- package/dist/gemini/docs/genai/python/DOC.md +555 -0
- package/dist/github/docs/octokit/DOC.md +1560 -0
- package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
- package/dist/google/docs/bigquery/python/DOC.md +1503 -0
- package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
- package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
- package/dist/huggingface/docs/transformers/DOC.md +948 -0
- package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
- package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
- package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
- package/dist/jira/docs/issues/python/DOC.md +1492 -0
- package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
- package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
- package/dist/landingai-ade/docs/api/DOC.md +620 -0
- package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
- package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
- package/dist/landingai-ade/skills/SKILL.md +489 -0
- package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
- package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
- package/dist/linear/docs/tracker/DOC.md +1554 -0
- package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
- package/dist/livekit/docs/realtime/python/DOC.md +163 -0
- package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
- package/dist/meilisearch/docs/search/DOC.md +1241 -0
- package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
- package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
- package/dist/mongodb/docs/atlas/DOC.md +2041 -0
- package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
- package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
- package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
- package/dist/okta/docs/identity/python/DOC.md +1401 -0
- package/dist/openai/docs/chat/javascript/DOC.md +407 -0
- package/dist/openai/docs/chat/python/DOC.md +568 -0
- package/dist/paypal/docs/checkout/DOC.md +278 -0
- package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
- package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
- package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
- package/dist/plaid/docs/banking/python/DOC.md +1203 -0
- package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
- package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
- package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
- package/dist/prisma/docs/orm/python/DOC.md +1317 -0
- package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
- package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
- package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
- package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
- package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
- package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
- package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
- package/dist/redis/docs/key-value/python/DOC.md +2054 -0
- package/dist/registry.json +2817 -0
- package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
- package/dist/resend/docs/email/DOC.md +1271 -0
- package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
- package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
- package/dist/search-index.json +1 -0
- package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
- package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
- package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
- package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
- package/dist/shopify/docs/storefront/DOC.md +457 -0
- package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
- package/dist/slack/docs/workspace/python/DOC.md +271 -0
- package/dist/square/docs/payments/javascript/DOC.md +1855 -0
- package/dist/square/docs/payments/python/DOC.md +1728 -0
- package/dist/stripe/docs/api/DOC.md +1727 -0
- package/dist/stripe/docs/payments/DOC.md +1726 -0
- package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
- package/dist/stytch/docs/auth/python/DOC.md +1962 -0
- package/dist/supabase/docs/client/DOC.md +1606 -0
- package/dist/twilio/docs/messaging/python/DOC.md +469 -0
- package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
- package/dist/vercel/docs/platform/DOC.md +1940 -0
- package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
- package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
- package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
- package/dist/zendesk/docs/support/python/DOC.md +2297 -0
- package/package.json +22 -6
- package/skills/get-api-docs/SKILL.md +84 -0
- package/src/commands/annotate.js +83 -0
- package/src/commands/build.js +12 -1
- package/src/commands/feedback.js +150 -0
- package/src/commands/get.js +83 -42
- package/src/commands/search.js +7 -0
- package/src/index.js +43 -17
- package/src/lib/analytics.js +90 -0
- package/src/lib/annotations.js +57 -0
- package/src/lib/bm25.js +170 -0
- package/src/lib/cache.js +69 -6
- package/src/lib/config.js +8 -3
- package/src/lib/identity.js +99 -0
- package/src/lib/registry.js +103 -20
- package/src/lib/telemetry.js +86 -0
- package/src/mcp/server.js +177 -0
- package/src/mcp/tools.js +251 -0
|
@@ -0,0 +1,1015 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: auth
|
|
3
|
+
description: "Firebase Authentication JavaScript SDK - Comprehensive coding guide for Firebase auth in JavaScript projects"
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "javascript"
|
|
6
|
+
versions: "12.4.0"
|
|
7
|
+
updated-on: "2026-03-02"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "firebase,auth,google,identity,session"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Firebase Authentication JavaScript SDK - Comprehensive Coding Guide
|
|
13
|
+
|
|
14
|
+
## 1. Golden Rule
|
|
15
|
+
|
|
16
|
+
**Always use the official Firebase Authentication package:**
|
|
17
|
+
- Package: `firebase/auth` (modular SDK)
|
|
18
|
+
- Legacy: `@firebase/auth` (use only if maintaining legacy code)
|
|
19
|
+
|
|
20
|
+
**Never use deprecated Firebase namespaced imports.** The modular SDK is the only recommended approach for new projects.
|
|
21
|
+
|
|
22
|
+
## 2. Installation
|
|
23
|
+
|
|
24
|
+
### npm
|
|
25
|
+
```bash
|
|
26
|
+
npm install firebase
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### yarn
|
|
30
|
+
```bash
|
|
31
|
+
yarn add firebase
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### pnpm
|
|
35
|
+
```bash
|
|
36
|
+
pnpm add firebase
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Environment Variables (Optional):**
|
|
40
|
+
```bash
|
|
41
|
+
FIREBASE_API_KEY=your_api_key_here
|
|
42
|
+
FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
|
|
43
|
+
FIREBASE_PROJECT_ID=your-project-id
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 3. Initialization
|
|
47
|
+
|
|
48
|
+
### Basic Initialization
|
|
49
|
+
```javascript
|
|
50
|
+
import { initializeApp } from 'firebase/app';
|
|
51
|
+
import { getAuth } from 'firebase/auth';
|
|
52
|
+
|
|
53
|
+
const firebaseConfig = {
|
|
54
|
+
apiKey: "your-api-key",
|
|
55
|
+
authDomain: "your-project.firebaseapp.com",
|
|
56
|
+
projectId: "your-project-id"
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const app = initializeApp(firebaseConfig);
|
|
60
|
+
const auth = getAuth(app);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Advanced Initialization
|
|
64
|
+
|
|
65
|
+
#### Custom Settings with Dependencies
|
|
66
|
+
```javascript
|
|
67
|
+
import {
|
|
68
|
+
initializeAuth,
|
|
69
|
+
browserLocalPersistence,
|
|
70
|
+
browserPopupRedirectResolver
|
|
71
|
+
} from 'firebase/auth';
|
|
72
|
+
|
|
73
|
+
const auth = initializeAuth(app, {
|
|
74
|
+
persistence: browserLocalPersistence,
|
|
75
|
+
popupRedirectResolver: browserPopupRedirectResolver
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### Cordova/Capacitor Initialization
|
|
80
|
+
```javascript
|
|
81
|
+
import {
|
|
82
|
+
initializeAuth,
|
|
83
|
+
indexedDBLocalPersistence,
|
|
84
|
+
cordovaPopupRedirectResolver
|
|
85
|
+
} from 'firebase/auth';
|
|
86
|
+
|
|
87
|
+
const auth = initializeAuth(app, {
|
|
88
|
+
persistence: indexedDBLocalPersistence,
|
|
89
|
+
popupRedirectResolver: cordovaPopupRedirectResolver
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Emulator Connection
|
|
94
|
+
```javascript
|
|
95
|
+
import { connectAuthEmulator } from 'firebase/auth';
|
|
96
|
+
|
|
97
|
+
// Connect to local emulator (must be called before any operations)
|
|
98
|
+
connectAuthEmulator(auth, 'http://localhost:9099');
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 4. Core API Surfaces
|
|
102
|
+
|
|
103
|
+
### Email/Password Authentication
|
|
104
|
+
|
|
105
|
+
#### Minimal Example - Sign Up
|
|
106
|
+
```javascript
|
|
107
|
+
import { createUserWithEmailAndPassword } from 'firebase/auth';
|
|
108
|
+
|
|
109
|
+
const userCredential = await createUserWithEmailAndPassword(
|
|
110
|
+
auth,
|
|
111
|
+
'user@example.com',
|
|
112
|
+
'password123'
|
|
113
|
+
);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### Minimal Example - Sign In
|
|
117
|
+
```javascript
|
|
118
|
+
import { signInWithEmailAndPassword } from 'firebase/auth';
|
|
119
|
+
|
|
120
|
+
const userCredential = await signInWithEmailAndPassword(
|
|
121
|
+
auth,
|
|
122
|
+
'user@example.com',
|
|
123
|
+
'password123'
|
|
124
|
+
);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Minimal Example - Sign Out
|
|
128
|
+
```javascript
|
|
129
|
+
import { signOut } from 'firebase/auth';
|
|
130
|
+
|
|
131
|
+
await signOut(auth);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Advanced Example - Password Reset
|
|
135
|
+
```javascript
|
|
136
|
+
import { sendPasswordResetEmail } from 'firebase/auth';
|
|
137
|
+
|
|
138
|
+
await sendPasswordResetEmail(auth, 'user@example.com', {
|
|
139
|
+
url: 'https://myapp.com/login',
|
|
140
|
+
handleCodeInApp: false
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### Advanced Example - Update Password
|
|
145
|
+
```javascript
|
|
146
|
+
import { updatePassword } from 'firebase/auth';
|
|
147
|
+
|
|
148
|
+
const user = auth.currentUser;
|
|
149
|
+
await updatePassword(user, 'newPassword123');
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### Email Verification
|
|
153
|
+
```javascript
|
|
154
|
+
import { sendEmailVerification } from 'firebase/auth';
|
|
155
|
+
|
|
156
|
+
const user = auth.currentUser;
|
|
157
|
+
await sendEmailVerification(user, {
|
|
158
|
+
url: 'https://myapp.com/verify',
|
|
159
|
+
handleCodeInApp: true
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Social Authentication (OAuth Providers)
|
|
164
|
+
|
|
165
|
+
#### Minimal Example - Google Sign In (Popup)
|
|
166
|
+
```javascript
|
|
167
|
+
import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
|
|
168
|
+
|
|
169
|
+
const provider = new GoogleAuthProvider();
|
|
170
|
+
const result = await signInWithPopup(auth, provider);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### Advanced Example - Google Sign In with Scopes
|
|
174
|
+
```javascript
|
|
175
|
+
import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
|
|
176
|
+
|
|
177
|
+
const provider = new GoogleAuthProvider();
|
|
178
|
+
provider.addScope('https://www.googleapis.com/auth/contacts.readonly');
|
|
179
|
+
provider.setCustomParameters({
|
|
180
|
+
prompt: 'select_account'
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const result = await signInWithPopup(auth, provider);
|
|
184
|
+
const credential = GoogleAuthProvider.credentialFromResult(result);
|
|
185
|
+
const accessToken = credential.accessToken;
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### Redirect Flow (Mobile/Better UX)
|
|
189
|
+
```javascript
|
|
190
|
+
import { signInWithRedirect, getRedirectResult, GoogleAuthProvider } from 'firebase/auth';
|
|
191
|
+
|
|
192
|
+
// Initiate redirect
|
|
193
|
+
const provider = new GoogleAuthProvider();
|
|
194
|
+
await signInWithRedirect(auth, provider);
|
|
195
|
+
|
|
196
|
+
// After redirect, get result
|
|
197
|
+
const result = await getRedirectResult(auth);
|
|
198
|
+
if (result) {
|
|
199
|
+
const user = result.user;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### Facebook Authentication
|
|
204
|
+
```javascript
|
|
205
|
+
import { signInWithPopup, FacebookAuthProvider } from 'firebase/auth';
|
|
206
|
+
|
|
207
|
+
const provider = new FacebookAuthProvider();
|
|
208
|
+
provider.addScope('user_birthday');
|
|
209
|
+
const result = await signInWithPopup(auth, provider);
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### GitHub Authentication
|
|
213
|
+
```javascript
|
|
214
|
+
import { signInWithPopup, GithubAuthProvider } from 'firebase/auth';
|
|
215
|
+
|
|
216
|
+
const provider = new GithubAuthProvider();
|
|
217
|
+
provider.addScope('repo');
|
|
218
|
+
const result = await signInWithPopup(auth, provider);
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### Twitter/X Authentication
|
|
222
|
+
```javascript
|
|
223
|
+
import { signInWithPopup, TwitterAuthProvider } from 'firebase/auth';
|
|
224
|
+
|
|
225
|
+
const provider = new TwitterAuthProvider();
|
|
226
|
+
const result = await signInWithPopup(auth, provider);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### Microsoft Authentication
|
|
230
|
+
```javascript
|
|
231
|
+
import { signInWithPopup, OAuthProvider } from 'firebase/auth';
|
|
232
|
+
|
|
233
|
+
const provider = new OAuthProvider('microsoft.com');
|
|
234
|
+
provider.addScope('mail.read');
|
|
235
|
+
const result = await signInWithPopup(auth, provider);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### Apple Authentication
|
|
239
|
+
```javascript
|
|
240
|
+
import { signInWithPopup, OAuthProvider } from 'firebase/auth';
|
|
241
|
+
|
|
242
|
+
const provider = new OAuthProvider('apple.com');
|
|
243
|
+
provider.addScope('email');
|
|
244
|
+
provider.addScope('name');
|
|
245
|
+
const result = await signInWithPopup(auth, provider);
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Phone Authentication
|
|
249
|
+
|
|
250
|
+
#### Minimal Example - Send Verification Code
|
|
251
|
+
```javascript
|
|
252
|
+
import { RecaptchaVerifier, signInWithPhoneNumber } from 'firebase/auth';
|
|
253
|
+
|
|
254
|
+
// Setup reCAPTCHA
|
|
255
|
+
const recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {
|
|
256
|
+
size: 'invisible'
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Send code
|
|
260
|
+
const confirmationResult = await signInWithPhoneNumber(
|
|
261
|
+
auth,
|
|
262
|
+
'+1234567890',
|
|
263
|
+
recaptchaVerifier
|
|
264
|
+
);
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### Advanced Example - Verify Code
|
|
268
|
+
```javascript
|
|
269
|
+
// User enters verification code
|
|
270
|
+
const code = '123456';
|
|
271
|
+
const result = await confirmationResult.confirm(code);
|
|
272
|
+
const user = result.user;
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
#### Visible reCAPTCHA
|
|
276
|
+
```javascript
|
|
277
|
+
const recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {
|
|
278
|
+
size: 'normal',
|
|
279
|
+
callback: (response) => {
|
|
280
|
+
// reCAPTCHA solved
|
|
281
|
+
},
|
|
282
|
+
'expired-callback': () => {
|
|
283
|
+
// reCAPTCHA expired
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
recaptchaVerifier.render();
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Anonymous Authentication
|
|
291
|
+
|
|
292
|
+
#### Minimal Example
|
|
293
|
+
```javascript
|
|
294
|
+
import { signInAnonymously } from 'firebase/auth';
|
|
295
|
+
|
|
296
|
+
const userCredential = await signInAnonymously(auth);
|
|
297
|
+
const user = userCredential.user;
|
|
298
|
+
console.log('Anonymous user ID:', user.uid);
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
#### Link Anonymous Account to Email
|
|
302
|
+
```javascript
|
|
303
|
+
import { linkWithCredential, EmailAuthProvider } from 'firebase/auth';
|
|
304
|
+
|
|
305
|
+
const credential = EmailAuthProvider.credential('user@example.com', 'password123');
|
|
306
|
+
const userCredential = await linkWithCredential(auth.currentUser, credential);
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Custom Token Authentication
|
|
310
|
+
|
|
311
|
+
#### Minimal Example
|
|
312
|
+
```javascript
|
|
313
|
+
import { signInWithCustomToken } from 'firebase/auth';
|
|
314
|
+
|
|
315
|
+
// Token generated on your server
|
|
316
|
+
const customToken = 'your-custom-token';
|
|
317
|
+
const userCredential = await signInWithCustomToken(auth, customToken);
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Email Link Authentication
|
|
321
|
+
|
|
322
|
+
#### Send Sign-In Link
|
|
323
|
+
```javascript
|
|
324
|
+
import { sendSignInLinkToEmail } from 'firebase/auth';
|
|
325
|
+
|
|
326
|
+
const actionCodeSettings = {
|
|
327
|
+
url: 'https://www.example.com/finishSignUp?cartId=1234',
|
|
328
|
+
handleCodeInApp: true,
|
|
329
|
+
iOS: {
|
|
330
|
+
bundleId: 'com.example.ios'
|
|
331
|
+
},
|
|
332
|
+
android: {
|
|
333
|
+
packageName: 'com.example.android',
|
|
334
|
+
installApp: true,
|
|
335
|
+
minimumVersion: '12'
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
await sendSignInLinkToEmail(auth, 'user@example.com', actionCodeSettings);
|
|
340
|
+
// Save email to verify after redirect
|
|
341
|
+
window.localStorage.setItem('emailForSignIn', 'user@example.com');
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
#### Complete Sign-In with Email Link
|
|
345
|
+
```javascript
|
|
346
|
+
import { isSignInWithEmailLink, signInWithEmailLink } from 'firebase/auth';
|
|
347
|
+
|
|
348
|
+
// Confirm the link is a sign-in with email link
|
|
349
|
+
if (isSignInWithEmailLink(auth, window.location.href)) {
|
|
350
|
+
let email = window.localStorage.getItem('emailForSignIn');
|
|
351
|
+
if (!email) {
|
|
352
|
+
email = window.prompt('Please provide your email for confirmation');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const result = await signInWithEmailLink(auth, email, window.location.href);
|
|
356
|
+
window.localStorage.removeItem('emailForSignIn');
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### SAML Authentication
|
|
361
|
+
|
|
362
|
+
#### Sign In with SAML
|
|
363
|
+
```javascript
|
|
364
|
+
import { signInWithPopup, SAMLAuthProvider } from 'firebase/auth';
|
|
365
|
+
|
|
366
|
+
const provider = new SAMLAuthProvider('saml.provider-id');
|
|
367
|
+
const result = await signInWithPopup(auth, provider);
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Multi-Factor Authentication (MFA)
|
|
371
|
+
|
|
372
|
+
#### Enroll User in Phone MFA
|
|
373
|
+
```javascript
|
|
374
|
+
import { multiFactor, PhoneAuthProvider, PhoneMultiFactorGenerator } from 'firebase/auth';
|
|
375
|
+
|
|
376
|
+
const user = auth.currentUser;
|
|
377
|
+
const multiFactorSession = await multiFactor(user).getSession();
|
|
378
|
+
|
|
379
|
+
const phoneAuthProvider = new PhoneAuthProvider(auth);
|
|
380
|
+
const verificationId = await phoneAuthProvider.verifyPhoneNumber(
|
|
381
|
+
'+1234567890',
|
|
382
|
+
recaptchaVerifier,
|
|
383
|
+
multiFactorSession
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
const verificationCode = '123456'; // User enters code
|
|
387
|
+
const phoneAuthCredential = PhoneAuthProvider.credential(verificationId, verificationCode);
|
|
388
|
+
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(phoneAuthCredential);
|
|
389
|
+
|
|
390
|
+
await multiFactor(user).enroll(multiFactorAssertion, 'Personal phone');
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
#### Enroll User in TOTP MFA
|
|
394
|
+
```javascript
|
|
395
|
+
import { multiFactor, TotpMultiFactorGenerator, TotpSecret } from 'firebase/auth';
|
|
396
|
+
|
|
397
|
+
const user = auth.currentUser;
|
|
398
|
+
const multiFactorSession = await multiFactor(user).getSession();
|
|
399
|
+
|
|
400
|
+
// Generate TOTP secret
|
|
401
|
+
const totpSecret = await TotpSecret.generate(auth, multiFactorSession);
|
|
402
|
+
|
|
403
|
+
// Display QR code to user
|
|
404
|
+
const qrCodeUrl = totpSecret.generateQrCodeUrl(user.email, 'MyApp');
|
|
405
|
+
console.log('QR Code URL:', qrCodeUrl);
|
|
406
|
+
|
|
407
|
+
// User scans QR code and enters verification code
|
|
408
|
+
const verificationCode = '123456';
|
|
409
|
+
const multiFactorAssertion = TotpMultiFactorGenerator.assertionForEnrollment(
|
|
410
|
+
totpSecret,
|
|
411
|
+
verificationCode
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
await multiFactor(user).enroll(multiFactorAssertion, 'TOTP device');
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
#### Sign In with Phone MFA
|
|
418
|
+
```javascript
|
|
419
|
+
import { getMultiFactorResolver, PhoneAuthProvider, PhoneMultiFactorGenerator } from 'firebase/auth';
|
|
420
|
+
|
|
421
|
+
try {
|
|
422
|
+
await signInWithEmailAndPassword(auth, email, password);
|
|
423
|
+
} catch (error) {
|
|
424
|
+
if (error.code === 'auth/multi-factor-auth-required') {
|
|
425
|
+
const resolver = getMultiFactorResolver(auth, error);
|
|
426
|
+
|
|
427
|
+
const phoneAuthProvider = new PhoneAuthProvider(auth);
|
|
428
|
+
const verificationId = await phoneAuthProvider.verifyPhoneNumber(
|
|
429
|
+
resolver.hints[0].phoneNumber,
|
|
430
|
+
recaptchaVerifier
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
const verificationCode = '123456'; // User enters code
|
|
434
|
+
const phoneAuthCredential = PhoneAuthProvider.credential(verificationId, verificationCode);
|
|
435
|
+
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(phoneAuthCredential);
|
|
436
|
+
|
|
437
|
+
const userCredential = await resolver.resolveSignIn(multiFactorAssertion);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
#### Sign In with TOTP MFA
|
|
443
|
+
```javascript
|
|
444
|
+
import { getMultiFactorResolver, TotpMultiFactorGenerator } from 'firebase/auth';
|
|
445
|
+
|
|
446
|
+
try {
|
|
447
|
+
await signInWithEmailAndPassword(auth, email, password);
|
|
448
|
+
} catch (error) {
|
|
449
|
+
if (error.code === 'auth/multi-factor-auth-required') {
|
|
450
|
+
const resolver = getMultiFactorResolver(auth, error);
|
|
451
|
+
|
|
452
|
+
// Select TOTP factor
|
|
453
|
+
const totpInfo = resolver.hints.find(hint => hint.factorId === 'totp');
|
|
454
|
+
|
|
455
|
+
const verificationCode = '123456'; // User enters TOTP code
|
|
456
|
+
const multiFactorAssertion = TotpMultiFactorGenerator.assertionForSignIn(
|
|
457
|
+
totpInfo.uid,
|
|
458
|
+
verificationCode
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
const userCredential = await resolver.resolveSignIn(multiFactorAssertion);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
#### Unenroll from MFA
|
|
467
|
+
```javascript
|
|
468
|
+
import { multiFactor } from 'firebase/auth';
|
|
469
|
+
|
|
470
|
+
const user = auth.currentUser;
|
|
471
|
+
const enrolledFactors = multiFactor(user).enrolledFactors;
|
|
472
|
+
|
|
473
|
+
// Unenroll from specific factor
|
|
474
|
+
await multiFactor(user).unenroll(enrolledFactors[0]);
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## 5. Advanced Features
|
|
478
|
+
|
|
479
|
+
### User State Management
|
|
480
|
+
|
|
481
|
+
#### Auth State Observer
|
|
482
|
+
```javascript
|
|
483
|
+
import { onAuthStateChanged } from 'firebase/auth';
|
|
484
|
+
|
|
485
|
+
const unsubscribe = onAuthStateChanged(auth, (user) => {
|
|
486
|
+
if (user) {
|
|
487
|
+
console.log('User is signed in:', user.uid);
|
|
488
|
+
} else {
|
|
489
|
+
console.log('User is signed out');
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
// Cleanup
|
|
494
|
+
unsubscribe();
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
#### ID Token Changed Listener
|
|
498
|
+
```javascript
|
|
499
|
+
import { onIdTokenChanged } from 'firebase/auth';
|
|
500
|
+
|
|
501
|
+
const unsubscribe = onIdTokenChanged(auth, (user) => {
|
|
502
|
+
if (user) {
|
|
503
|
+
// Get fresh token
|
|
504
|
+
user.getIdToken().then((token) => {
|
|
505
|
+
console.log('Fresh token:', token);
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
#### Before Auth State Changed (Blocking Callback)
|
|
512
|
+
```javascript
|
|
513
|
+
import { beforeAuthStateChanged } from 'firebase/auth';
|
|
514
|
+
|
|
515
|
+
const unsubscribe = beforeAuthStateChanged(
|
|
516
|
+
auth,
|
|
517
|
+
async (user) => {
|
|
518
|
+
// Runs before auth state changes
|
|
519
|
+
// Can be async and block the state change
|
|
520
|
+
if (user) {
|
|
521
|
+
console.log('User about to be set:', user.uid);
|
|
522
|
+
// Perform any necessary checks
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
() => {
|
|
526
|
+
// onAbort callback - called if a later beforeAuthStateChanged throws
|
|
527
|
+
console.log('Auth state change was aborted');
|
|
528
|
+
}
|
|
529
|
+
);
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
#### Update Current User
|
|
533
|
+
```javascript
|
|
534
|
+
import { updateCurrentUser } from 'firebase/auth';
|
|
535
|
+
|
|
536
|
+
// Set a different user as current user
|
|
537
|
+
await updateCurrentUser(auth, newUser);
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
#### Get Current User
|
|
541
|
+
```javascript
|
|
542
|
+
const user = auth.currentUser;
|
|
543
|
+
|
|
544
|
+
if (user) {
|
|
545
|
+
console.log('User ID:', user.uid);
|
|
546
|
+
console.log('Email:', user.email);
|
|
547
|
+
console.log('Display Name:', user.displayName);
|
|
548
|
+
console.log('Photo URL:', user.photoURL);
|
|
549
|
+
console.log('Email Verified:', user.emailVerified);
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### User Profile Management
|
|
554
|
+
|
|
555
|
+
#### Update Profile
|
|
556
|
+
```javascript
|
|
557
|
+
import { updateProfile } from 'firebase/auth';
|
|
558
|
+
|
|
559
|
+
const user = auth.currentUser;
|
|
560
|
+
await updateProfile(user, {
|
|
561
|
+
displayName: 'John Doe',
|
|
562
|
+
photoURL: 'https://example.com/photo.jpg'
|
|
563
|
+
});
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
#### Update Email (Deprecated)
|
|
567
|
+
```javascript
|
|
568
|
+
import { updateEmail, sendEmailVerification } from 'firebase/auth';
|
|
569
|
+
|
|
570
|
+
const user = auth.currentUser;
|
|
571
|
+
await updateEmail(user, 'newemail@example.com');
|
|
572
|
+
await sendEmailVerification(user);
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
#### Update Email with Verification (Recommended)
|
|
576
|
+
```javascript
|
|
577
|
+
import { verifyBeforeUpdateEmail } from 'firebase/auth';
|
|
578
|
+
|
|
579
|
+
const actionCodeSettings = {
|
|
580
|
+
url: 'https://www.example.com/?email=user@example.com'
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
const user = auth.currentUser;
|
|
584
|
+
await verifyBeforeUpdateEmail(user, 'newemail@example.com', actionCodeSettings);
|
|
585
|
+
// User must verify new email before it takes effect
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
#### Update Phone Number
|
|
589
|
+
```javascript
|
|
590
|
+
import { updatePhoneNumber, PhoneAuthProvider } from 'firebase/auth';
|
|
591
|
+
|
|
592
|
+
// First get phone credential
|
|
593
|
+
const phoneAuthProvider = new PhoneAuthProvider(auth);
|
|
594
|
+
const verificationId = await phoneAuthProvider.verifyPhoneNumber(
|
|
595
|
+
'+1234567890',
|
|
596
|
+
recaptchaVerifier
|
|
597
|
+
);
|
|
598
|
+
|
|
599
|
+
const verificationCode = '123456'; // User enters code
|
|
600
|
+
const phoneCredential = PhoneAuthProvider.credential(verificationId, verificationCode);
|
|
601
|
+
|
|
602
|
+
const user = auth.currentUser;
|
|
603
|
+
await updatePhoneNumber(user, phoneCredential);
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
#### Reload User Data
|
|
607
|
+
```javascript
|
|
608
|
+
import { reload } from 'firebase/auth';
|
|
609
|
+
|
|
610
|
+
await reload(auth.currentUser);
|
|
611
|
+
const updatedUser = auth.currentUser;
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
#### Delete User Account
|
|
615
|
+
```javascript
|
|
616
|
+
import { deleteUser } from 'firebase/auth';
|
|
617
|
+
|
|
618
|
+
const user = auth.currentUser;
|
|
619
|
+
await deleteUser(user);
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Token Management
|
|
623
|
+
|
|
624
|
+
#### Get ID Token
|
|
625
|
+
```javascript
|
|
626
|
+
const user = auth.currentUser;
|
|
627
|
+
const token = await user.getIdToken();
|
|
628
|
+
const refreshedToken = await user.getIdToken(true); // Force refresh
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
#### Get ID Token Result (with Claims)
|
|
632
|
+
```javascript
|
|
633
|
+
import { getIdToken, getIdTokenResult } from 'firebase/auth';
|
|
634
|
+
|
|
635
|
+
const user = auth.currentUser;
|
|
636
|
+
|
|
637
|
+
// Using user method
|
|
638
|
+
const token = await getIdToken(user);
|
|
639
|
+
const idTokenResult = await getIdTokenResult(user);
|
|
640
|
+
|
|
641
|
+
console.log('Token:', idTokenResult.token);
|
|
642
|
+
console.log('Expiration:', idTokenResult.expirationTime);
|
|
643
|
+
console.log('Custom Claims:', idTokenResult.claims);
|
|
644
|
+
console.log('Auth Time:', idTokenResult.authTime);
|
|
645
|
+
console.log('Issued At:', idTokenResult.issuedAtTime);
|
|
646
|
+
console.log('Sign-in Provider:', idTokenResult.signInProvider);
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Password Validation
|
|
650
|
+
|
|
651
|
+
#### Validate Password Against Policy
|
|
652
|
+
```javascript
|
|
653
|
+
import { validatePassword } from 'firebase/auth';
|
|
654
|
+
|
|
655
|
+
const validationStatus = await validatePassword(auth, 'MyPassword123!');
|
|
656
|
+
|
|
657
|
+
console.log('Is valid:', validationStatus.isValid);
|
|
658
|
+
console.log('Contains lowercase:', validationStatus.containsLowercaseLetter);
|
|
659
|
+
console.log('Contains uppercase:', validationStatus.containsUppercaseLetter);
|
|
660
|
+
console.log('Contains numeric:', validationStatus.containsNumericCharacter);
|
|
661
|
+
console.log('Contains non-alphanumeric:', validationStatus.containsNonAlphanumericCharacter);
|
|
662
|
+
console.log('Meets min length:', validationStatus.meetsMinPasswordLength);
|
|
663
|
+
console.log('Meets max length:', validationStatus.meetsMaxPasswordLength);
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
### Account Linking
|
|
667
|
+
|
|
668
|
+
#### Link Multiple Providers
|
|
669
|
+
```javascript
|
|
670
|
+
import { linkWithPopup, GoogleAuthProvider } from 'firebase/auth';
|
|
671
|
+
|
|
672
|
+
const provider = new GoogleAuthProvider();
|
|
673
|
+
const result = await linkWithPopup(auth.currentUser, provider);
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
#### Link with Credential
|
|
677
|
+
```javascript
|
|
678
|
+
import { linkWithCredential, EmailAuthProvider } from 'firebase/auth';
|
|
679
|
+
|
|
680
|
+
const credential = EmailAuthProvider.credential('user@example.com', 'password123');
|
|
681
|
+
await linkWithCredential(auth.currentUser, credential);
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
#### Link with Phone Number
|
|
685
|
+
```javascript
|
|
686
|
+
import { linkWithPhoneNumber } from 'firebase/auth';
|
|
687
|
+
|
|
688
|
+
const confirmationResult = await linkWithPhoneNumber(
|
|
689
|
+
auth.currentUser,
|
|
690
|
+
'+1234567890',
|
|
691
|
+
recaptchaVerifier
|
|
692
|
+
);
|
|
693
|
+
|
|
694
|
+
const verificationCode = '123456';
|
|
695
|
+
await confirmationResult.confirm(verificationCode);
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
#### Link with Redirect
|
|
699
|
+
```javascript
|
|
700
|
+
import { linkWithRedirect, GoogleAuthProvider } from 'firebase/auth';
|
|
701
|
+
|
|
702
|
+
const provider = new GoogleAuthProvider();
|
|
703
|
+
await linkWithRedirect(auth.currentUser, provider);
|
|
704
|
+
|
|
705
|
+
// After redirect, check result
|
|
706
|
+
const result = await getRedirectResult(auth);
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
#### Unlink Provider
|
|
710
|
+
```javascript
|
|
711
|
+
import { unlink } from 'firebase/auth';
|
|
712
|
+
|
|
713
|
+
await unlink(auth.currentUser, 'google.com');
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
#### Fetch Sign-In Methods
|
|
717
|
+
```javascript
|
|
718
|
+
import { fetchSignInMethodsForEmail } from 'firebase/auth';
|
|
719
|
+
|
|
720
|
+
const methods = await fetchSignInMethodsForEmail(auth, 'user@example.com');
|
|
721
|
+
console.log('Available sign-in methods:', methods);
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
### Re-authentication
|
|
725
|
+
|
|
726
|
+
#### Re-authenticate User
|
|
727
|
+
```javascript
|
|
728
|
+
import { reauthenticateWithCredential, EmailAuthProvider } from 'firebase/auth';
|
|
729
|
+
|
|
730
|
+
const user = auth.currentUser;
|
|
731
|
+
const credential = EmailAuthProvider.credential(user.email, 'current-password');
|
|
732
|
+
|
|
733
|
+
await reauthenticateWithCredential(user, credential);
|
|
734
|
+
// Now perform sensitive operations
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
#### Re-authenticate with Popup
|
|
738
|
+
```javascript
|
|
739
|
+
import { reauthenticateWithPopup, GoogleAuthProvider } from 'firebase/auth';
|
|
740
|
+
|
|
741
|
+
const provider = new GoogleAuthProvider();
|
|
742
|
+
await reauthenticateWithPopup(auth.currentUser, provider);
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
#### Re-authenticate with Redirect
|
|
746
|
+
```javascript
|
|
747
|
+
import { reauthenticateWithRedirect, GoogleAuthProvider } from 'firebase/auth';
|
|
748
|
+
|
|
749
|
+
const provider = new GoogleAuthProvider();
|
|
750
|
+
await reauthenticateWithRedirect(auth.currentUser, provider);
|
|
751
|
+
|
|
752
|
+
// After redirect
|
|
753
|
+
const result = await getRedirectResult(auth);
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
#### Re-authenticate with Phone Number
|
|
757
|
+
```javascript
|
|
758
|
+
import { reauthenticateWithPhoneNumber } from 'firebase/auth';
|
|
759
|
+
|
|
760
|
+
const confirmationResult = await reauthenticateWithPhoneNumber(
|
|
761
|
+
auth.currentUser,
|
|
762
|
+
'+1234567890',
|
|
763
|
+
recaptchaVerifier
|
|
764
|
+
);
|
|
765
|
+
|
|
766
|
+
const verificationCode = '123456';
|
|
767
|
+
await confirmationResult.confirm(verificationCode);
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
### Session Persistence
|
|
771
|
+
|
|
772
|
+
#### Set Persistence (Browser)
|
|
773
|
+
```javascript
|
|
774
|
+
import {
|
|
775
|
+
setPersistence,
|
|
776
|
+
browserLocalPersistence,
|
|
777
|
+
browserSessionPersistence,
|
|
778
|
+
inMemoryPersistence,
|
|
779
|
+
indexedDBLocalPersistence
|
|
780
|
+
} from 'firebase/auth';
|
|
781
|
+
|
|
782
|
+
// Local persistence using localStorage (survives browser restart)
|
|
783
|
+
await setPersistence(auth, browserLocalPersistence);
|
|
784
|
+
|
|
785
|
+
// Session persistence using sessionStorage (survives page refresh only)
|
|
786
|
+
await setPersistence(auth, browserSessionPersistence);
|
|
787
|
+
|
|
788
|
+
// No persistence (memory only)
|
|
789
|
+
await setPersistence(auth, inMemoryPersistence);
|
|
790
|
+
|
|
791
|
+
// IndexedDB persistence (recommended for large data)
|
|
792
|
+
await setPersistence(auth, indexedDBLocalPersistence);
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
#### React Native Persistence
|
|
796
|
+
```javascript
|
|
797
|
+
import { initializeAuth, getReactNativePersistence } from 'firebase/auth';
|
|
798
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
799
|
+
|
|
800
|
+
const auth = initializeAuth(app, {
|
|
801
|
+
persistence: getReactNativePersistence(AsyncStorage)
|
|
802
|
+
});
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
#### Cookie Persistence (Public Preview)
|
|
806
|
+
```javascript
|
|
807
|
+
import { setPersistence, browserCookiePersistence } from 'firebase/auth';
|
|
808
|
+
|
|
809
|
+
// For hybrid rendering and middleware applications
|
|
810
|
+
await setPersistence(auth, browserCookiePersistence);
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
### Language and Localization
|
|
814
|
+
|
|
815
|
+
#### Use Device Language
|
|
816
|
+
```javascript
|
|
817
|
+
import { useDeviceLanguage } from 'firebase/auth';
|
|
818
|
+
|
|
819
|
+
useDeviceLanguage(auth); // Use device language
|
|
820
|
+
|
|
821
|
+
// Or set specific language
|
|
822
|
+
auth.languageCode = 'es';
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
#### Initialize reCAPTCHA Config
|
|
826
|
+
```javascript
|
|
827
|
+
import { initializeRecaptchaConfig } from 'firebase/auth';
|
|
828
|
+
|
|
829
|
+
// Load reCAPTCHA config to reduce latency for auth flows
|
|
830
|
+
await initializeRecaptchaConfig(auth);
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
### Action Code Handling
|
|
834
|
+
|
|
835
|
+
#### Handle Password Reset Link
|
|
836
|
+
```javascript
|
|
837
|
+
import { verifyPasswordResetCode, confirmPasswordReset } from 'firebase/auth';
|
|
838
|
+
|
|
839
|
+
const actionCode = 'code-from-email-link';
|
|
840
|
+
|
|
841
|
+
// Verify code is valid
|
|
842
|
+
const email = await verifyPasswordResetCode(auth, actionCode);
|
|
843
|
+
|
|
844
|
+
// Reset password
|
|
845
|
+
await confirmPasswordReset(auth, actionCode, 'newPassword123');
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
#### Handle Email Verification
|
|
849
|
+
```javascript
|
|
850
|
+
import { applyActionCode } from 'firebase/auth';
|
|
851
|
+
|
|
852
|
+
const actionCode = 'code-from-email-link';
|
|
853
|
+
await applyActionCode(auth, actionCode);
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
#### Handle Email Change
|
|
857
|
+
```javascript
|
|
858
|
+
import { checkActionCode, applyActionCode } from 'firebase/auth';
|
|
859
|
+
|
|
860
|
+
const actionCode = 'code-from-email-link';
|
|
861
|
+
const info = await checkActionCode(auth, actionCode);
|
|
862
|
+
await applyActionCode(auth, actionCode);
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
#### Parse Action Code URL
|
|
866
|
+
```javascript
|
|
867
|
+
import { parseActionCodeURL } from 'firebase/auth';
|
|
868
|
+
|
|
869
|
+
const actionCodeUrl = parseActionCodeURL('https://example.com/action?mode=...');
|
|
870
|
+
|
|
871
|
+
if (actionCodeUrl) {
|
|
872
|
+
console.log('Mode:', actionCodeUrl.operation); // 'PASSWORD_RESET', 'VERIFY_EMAIL', etc.
|
|
873
|
+
console.log('Code:', actionCodeUrl.code);
|
|
874
|
+
console.log('Continue URL:', actionCodeUrl.continueUrl);
|
|
875
|
+
console.log('Language:', actionCodeUrl.languageCode);
|
|
876
|
+
}
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
### Additional User Info
|
|
880
|
+
|
|
881
|
+
#### Get Provider-Specific Info
|
|
882
|
+
```javascript
|
|
883
|
+
import { signInWithPopup, GoogleAuthProvider, getAdditionalUserInfo } from 'firebase/auth';
|
|
884
|
+
|
|
885
|
+
const provider = new GoogleAuthProvider();
|
|
886
|
+
const userCredential = await signInWithPopup(auth, provider);
|
|
887
|
+
|
|
888
|
+
const additionalInfo = getAdditionalUserInfo(userCredential);
|
|
889
|
+
console.log('Is new user:', additionalInfo.isNewUser);
|
|
890
|
+
console.log('Provider ID:', additionalInfo.providerId);
|
|
891
|
+
console.log('Profile:', additionalInfo.profile); // Provider-specific profile
|
|
892
|
+
console.log('Username:', additionalInfo.username); // GitHub/Twitter username
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
### Revoke Access Tokens
|
|
896
|
+
|
|
897
|
+
#### Revoke Apple OAuth Token
|
|
898
|
+
```javascript
|
|
899
|
+
import { revokeAccessToken } from 'firebase/auth';
|
|
900
|
+
|
|
901
|
+
// Revoke Apple OAuth access token
|
|
902
|
+
await revokeAccessToken(auth, appleAccessToken);
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
## 6. TypeScript Usage
|
|
906
|
+
|
|
907
|
+
### Import Types
|
|
908
|
+
```typescript
|
|
909
|
+
import type {
|
|
910
|
+
Auth,
|
|
911
|
+
User,
|
|
912
|
+
UserCredential,
|
|
913
|
+
AuthProvider,
|
|
914
|
+
AuthError,
|
|
915
|
+
IdTokenResult,
|
|
916
|
+
MultiFactorResolver,
|
|
917
|
+
Unsubscribe
|
|
918
|
+
} from 'firebase/auth';
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
### Type-Safe User Handling
|
|
922
|
+
```typescript
|
|
923
|
+
import { onAuthStateChanged, User } from 'firebase/auth';
|
|
924
|
+
|
|
925
|
+
onAuthStateChanged(auth, (user: User | null) => {
|
|
926
|
+
if (user) {
|
|
927
|
+
const uid: string = user.uid;
|
|
928
|
+
const email: string | null = user.email;
|
|
929
|
+
const emailVerified: boolean = user.emailVerified;
|
|
930
|
+
}
|
|
931
|
+
});
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
### Type-Safe Error Handling
|
|
935
|
+
```typescript
|
|
936
|
+
import { signInWithEmailAndPassword, AuthError } from 'firebase/auth';
|
|
937
|
+
|
|
938
|
+
try {
|
|
939
|
+
await signInWithEmailAndPassword(auth, email, password);
|
|
940
|
+
} catch (error) {
|
|
941
|
+
const authError = error as AuthError;
|
|
942
|
+
|
|
943
|
+
switch (authError.code) {
|
|
944
|
+
case 'auth/user-not-found':
|
|
945
|
+
console.error('User not found');
|
|
946
|
+
break;
|
|
947
|
+
case 'auth/wrong-password':
|
|
948
|
+
console.error('Wrong password');
|
|
949
|
+
break;
|
|
950
|
+
case 'auth/invalid-email':
|
|
951
|
+
console.error('Invalid email');
|
|
952
|
+
break;
|
|
953
|
+
default:
|
|
954
|
+
console.error('Authentication error:', authError.message);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
### Custom Claims Type
|
|
960
|
+
```typescript
|
|
961
|
+
interface CustomClaims {
|
|
962
|
+
admin?: boolean;
|
|
963
|
+
role?: string;
|
|
964
|
+
subscription?: string;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
const idTokenResult = await user.getIdTokenResult();
|
|
968
|
+
const claims = idTokenResult.claims as CustomClaims;
|
|
969
|
+
|
|
970
|
+
if (claims.admin) {
|
|
971
|
+
console.log('User is an admin');
|
|
972
|
+
}
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
## 7. OAuth Credential Handling
|
|
976
|
+
|
|
977
|
+
#### Sign In with OAuth Credential
|
|
978
|
+
```javascript
|
|
979
|
+
import { signInWithCredential, GoogleAuthProvider } from 'firebase/auth';
|
|
980
|
+
|
|
981
|
+
// Create credential from access token
|
|
982
|
+
const credential = GoogleAuthProvider.credential(idToken, accessToken);
|
|
983
|
+
await signInWithCredential(auth, credential);
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
#### Extract Credential from Result
|
|
987
|
+
```javascript
|
|
988
|
+
import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
|
|
989
|
+
|
|
990
|
+
const provider = new GoogleAuthProvider();
|
|
991
|
+
const result = await signInWithPopup(auth, provider);
|
|
992
|
+
|
|
993
|
+
// Get OAuth credential from result
|
|
994
|
+
const credential = GoogleAuthProvider.credentialFromResult(result);
|
|
995
|
+
const accessToken = credential.accessToken;
|
|
996
|
+
const idToken = credential.idToken;
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
#### Extract Credential from Error
|
|
1000
|
+
```javascript
|
|
1001
|
+
import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
|
|
1002
|
+
|
|
1003
|
+
try {
|
|
1004
|
+
await signInWithPopup(auth, provider);
|
|
1005
|
+
} catch (error) {
|
|
1006
|
+
// Extract credential that was being used
|
|
1007
|
+
const credential = GoogleAuthProvider.credentialFromError(error);
|
|
1008
|
+
|
|
1009
|
+
if (error.code === 'auth/account-exists-with-different-credential') {
|
|
1010
|
+
// Handle account linking
|
|
1011
|
+
const methods = await fetchSignInMethodsForEmail(auth, error.customData.email);
|
|
1012
|
+
// Proceed with account linking flow
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
```
|