@bagelink/auth 1.7.69 → 1.7.74

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
@@ -1,6 +1,16 @@
1
1
  # @bagelink/auth
2
2
 
3
- Authentication library for Bagelink applications with built-in SSO support, route management, and Vue components.
3
+ Modern authentication library for Bagelink applications with built-in SSO support, automatic redirect handling, and Vue components.
4
+
5
+ ## Features
6
+
7
+ - 🔐 **Complete auth flow** - Login, signup, password reset, email verification
8
+ - 🚀 **SSO ready** - Google, GitHub, Microsoft, Apple, Okta, Facebook
9
+ - 🔄 **Auto-redirect** - Handles post-login navigation automatically
10
+ - 🛡️ **Security built-in** - Protection against open redirect attacks
11
+ - 🎨 **Vue components** - Pre-built forms and pages
12
+ - 📱 **Type-safe** - Full TypeScript support
13
+ - 🧩 **Router integration** - Smart guards for protected routes
4
14
 
5
15
  ## Installation
6
16
 
@@ -13,381 +23,406 @@ npm install @bagelink/auth
13
23
  ### 1. Initialize Auth
14
24
 
15
25
  ```typescript
16
- import { createAuth } from '@bagelink/auth'
17
-
18
- createAuth({
19
- baseURL: 'https://api.your-app.com'
26
+ // main.ts
27
+ import { createApp } from 'vue'
28
+ import { createAuth, setAuthRouter, authGuard } from '@bagelink/auth'
29
+ import router from './router'
30
+
31
+ const auth = createAuth({
32
+ baseURL: 'https://api.your-app.com',
33
+ redirect: {
34
+ loginRoute: 'Login',
35
+ fallback: '/dashboard',
36
+ autoRedirect: true, // Automatic post-login redirect
37
+ }
20
38
  })
39
+
40
+ // Connect router for auto-redirect
41
+ setAuthRouter(router)
42
+
43
+ // Install auth guard
44
+ router.beforeEach(authGuard())
45
+
46
+ const app = createApp(App)
47
+ app.use(router)
48
+ app.use(auth) // Optional: adds $auth globally
49
+ app.mount('#app')
21
50
  ```
22
51
 
23
- ### 2. Add Routes
52
+ ### 2. Define Routes
24
53
 
25
54
  ```typescript
26
- import { createRouter } from 'vue-router'
27
- import { createAuthRoutes, createAuthGuard } from '@bagelink/auth'
28
-
29
- const router = createRouter({
55
+ // router/index.ts
56
+ import { createRouter, createWebHistory } from 'vue-router'
57
+
58
+ const routes = [
59
+ {
60
+ path: '/login',
61
+ name: 'Login',
62
+ component: () => import('@/views/Login.vue'),
63
+ },
64
+ {
65
+ path: '/dashboard',
66
+ name: 'Dashboard',
67
+ component: () => import('@/views/Dashboard.vue'),
68
+ meta: { auth: true }, // Protected route
69
+ },
70
+ ]
71
+
72
+ export default createRouter({
30
73
  history: createWebHistory(),
31
- routes: [
32
- // Add auth routes
33
- ...createAuthRoutes({
34
- basePath: '/auth',
35
- redirectTo: '/dashboard'
36
- }),
37
-
38
- // Your app routes
39
- {
40
- path: '/dashboard',
41
- component: Dashboard,
42
- meta: { requiresAuth: true }
43
- }
44
- ]
74
+ routes,
45
75
  })
46
-
47
- // Add auth guard to redirect authenticated users
48
- router.beforeEach(createAuthGuard({ redirectTo: '/dashboard' }))
49
-
50
- export default router
51
76
  ```
52
77
 
53
78
  ### 3. Use in Components
54
79
 
55
80
  ```vue
56
- <script setup>
81
+ <script setup lang="ts">
57
82
  import { useAuth } from '@bagelink/auth'
58
83
 
59
- const { user, logout, isAuthenticated } = useAuth()
84
+ const auth = useAuth()
85
+
86
+ async function handleLogin() {
87
+ await auth.login({
88
+ email: 'user@example.com',
89
+ password: 'password'
90
+ })
91
+ // Auto-redirect happens automatically! 🎉
92
+ }
60
93
  </script>
61
94
 
62
95
  <template>
63
- <div v-if="isAuthenticated">
64
- <p>Welcome, {{ user.name }}</p>
65
- <button @click="logout">Logout</button>
96
+ <div v-if="auth.user.value">
97
+ <p>Welcome, {{ auth.user.value.name }}!</p>
98
+ <button @click="auth.logout()">Logout</button>
66
99
  </div>
67
100
  </template>
68
101
  ```
69
102
 
70
- ## Route Configuration
103
+ ## Documentation
71
104
 
72
- ### Basic Setup
105
+ - **[REDIRECT_GUIDE.md](./REDIRECT_GUIDE.md)** - Complete redirect configuration guide
106
+ - **[COMPLETE_EXAMPLE.md](./COMPLETE_EXAMPLE.md)** - Full working application example
107
+ - **[BREAKING_CHANGES.md](./BREAKING_CHANGES.md)** - Migration guide for breaking changes
73
108
 
74
- ```typescript
75
- createAuthRoutes()
76
- // Creates routes: /login, /signup, /forgot-password, /reset-password, /callback
77
- ```
109
+ ## Core API
110
+
111
+ ### `createAuth(config)`
78
112
 
79
- ### Custom Base Path
113
+ Initialize the auth module with redirect configuration:
80
114
 
81
115
  ```typescript
82
- createAuthRoutes({
83
- basePath: '/auth'
116
+ createAuth({
117
+ baseURL: string, // Required: Your API base URL
118
+ redirect?: {
119
+ loginRoute?: string, // Login route name (default: 'Login')
120
+ fallback?: string, // Default redirect after login (default: '/')
121
+ queryKey?: string, // Query param for redirect URL (default: 'redirect')
122
+ autoRedirect?: boolean, // Auto-redirect after login (default: true)
123
+ preserveRedirect?: boolean, // Preserve original URL (default: true)
124
+ noAuthRoutes?: string[], // Routes requiring no auth (default: ['Login', 'Signup', ...])
125
+ allowedPaths?: RegExp[], // Optional: Restrict allowed redirects for security
126
+ }
84
127
  })
85
- // Creates routes: /auth/login, /auth/signup, etc.
86
128
  ```
87
129
 
88
- ### Custom Route Names
130
+ ### `useAuth()`
131
+
132
+ Returns auth composable with:
89
133
 
90
134
  ```typescript
91
- createAuthRoutes({
92
- routeNames: {
93
- login: 'UserLogin',
94
- signup: 'UserRegister',
95
- callback: 'OAuthCallback'
135
+ {
136
+ // State
137
+ user: Ref<User | null>
138
+ accountInfo: Ref<AccountInfo | null>
139
+
140
+ // Authentication
141
+ login(credentials): Promise<AuthenticationResponse>
142
+ signup(data): Promise<AuthenticationResponse>
143
+ logout(): Promise<void>
144
+ checkAuth(): Promise<boolean>
145
+
146
+ // SSO
147
+ sso: {
148
+ google: { redirect(), callback() }
149
+ github: { redirect(), callback() }
150
+ microsoft: { redirect(), callback() }
151
+ // ... more providers
96
152
  }
97
- })
153
+
154
+ // Password Management
155
+ forgotPassword(email): Promise<void>
156
+ resetPassword(token, newPassword): Promise<void>
157
+ changePassword(current, new): Promise<void>
158
+
159
+ // Profile
160
+ updateProfile(updates): Promise<void>
161
+
162
+ // Getters
163
+ getFullName(): string
164
+ getIsLoggedIn(): boolean
165
+ getEmail(): string
166
+ getRoles(): string[]
167
+ }
98
168
  ```
99
169
 
100
- ### With Layout Component
170
+ ### `authGuard()`
171
+
172
+ Navigation guard for protected routes:
101
173
 
102
174
  ```typescript
103
- import AuthLayout from './layouts/AuthLayout.vue'
175
+ router.beforeEach(authGuard()) // No parameters needed!
176
+ ```
104
177
 
105
- createAuthRoutes({
106
- layout: AuthLayout
107
- })
178
+ Protects routes with `meta: { auth: true }` and handles redirects automatically.
179
+
180
+ ### `setAuthRouter(router)`
181
+
182
+ Connect router for auto-redirect:
183
+
184
+ ```typescript
185
+ setAuthRouter(router) // Call after creating router
108
186
  ```
109
187
 
110
188
  ## Components
111
189
 
112
- ### Form Components
113
-
114
- Use these if you want to build custom pages:
190
+ ### Pre-built Pages
115
191
 
116
192
  ```vue
117
193
  <script setup>
118
- import { LoginForm, SignupForm } from '@bagelink/auth'
194
+ import { LoginPage, SignupPage, ForgotPasswordPage } from '@bagelink/auth'
119
195
  </script>
120
196
 
121
197
  <template>
122
- <LoginForm
198
+ <LoginPage
123
199
  :texts="{ title: 'Welcome Back' }"
124
- :show-github="true"
125
- :show-google="true"
126
- @switch-form="handleFormSwitch"
200
+ card-width="400px"
127
201
  />
128
202
  </template>
129
203
  ```
130
204
 
131
- ### Page Components
205
+ ### Form Components
132
206
 
133
- Pre-built page components with layout:
207
+ For custom layouts:
134
208
 
135
209
  ```vue
136
210
  <script setup>
137
- import { LoginPage } from '@bagelink/auth'
211
+ import { LoginForm, SignupForm } from '@bagelink/auth'
138
212
  </script>
139
213
 
140
214
  <template>
141
- <LoginPage
142
- :texts="{ title: 'Sign In' }"
143
- card-width="500px"
144
- />
215
+ <div class="custom-layout">
216
+ <LoginForm
217
+ :texts="{ title: 'Sign In' }"
218
+ :show-google="true"
219
+ :show-github="true"
220
+ />
221
+ </div>
145
222
  </template>
146
223
  ```
147
224
 
148
- ## SSO Configuration
149
-
150
- ### Available Providers
151
-
152
- - GitHub
153
- - Google
154
- - Microsoft
155
- - Apple
156
- - Okta
157
- - Facebook
225
+ ## SSO Integration
158
226
 
159
- ### Usage
227
+ ### Quick SSO Login
160
228
 
161
229
  ```typescript
162
230
  const { sso } = useAuth()
163
231
 
164
- // Initiate SSO login
165
- await sso.login('github')
166
-
167
- // Handle callback (automatically handled in /callback route)
168
- await sso.handleCallback()
169
-
170
- // Link additional account
171
- await sso.linkAccount('google')
232
+ // Redirect to Google OAuth
233
+ await sso.google.redirect({
234
+ redirect_uri: `${window.location.origin}/auth/callback`
235
+ })
172
236
  ```
173
237
 
174
- ### Customizing SSO Buttons
238
+ ### SSO Callback Route
175
239
 
176
- ```vue
177
- <LoginForm
178
- :show-github="true"
179
- :show-google="true"
180
- :show-microsoft="false"
181
- :sso-outline="true"
182
- :sso-show-value="true"
183
- :sso-brand-background="true"
184
- />
240
+ ```typescript
241
+ // router.ts
242
+ {
243
+ path: '/auth/callback',
244
+ name: 'Callback',
245
+ component: () => import('@bagelink/auth').then(m => m.Callback),
246
+ }
185
247
  ```
186
248
 
187
- ## API
188
-
189
- ### `useAuth()`
190
-
191
- Returns the authentication composable with:
249
+ ### Available Providers
192
250
 
193
- - `user` - Current user object (reactive)
194
- - `isAuthenticated` - Boolean indicating auth status (computed)
195
- - `accountInfo` - Extended account information (reactive)
196
- - `login(email, password)` - Login with credentials
197
- - `signup(data)` - Create new account
198
- - `logout()` - Logout current user
199
- - `forgotPassword(email)` - Request password reset
200
- - `resetPassword(token, password)` - Reset password with token
201
- - `sso` - SSO methods object
251
+ - Google
252
+ - GitHub
253
+ - Microsoft
254
+ - Apple
255
+ - Okta
256
+ - Facebook
202
257
 
203
- ### `createAuth(config)`
258
+ ## Advanced Configuration
204
259
 
205
- Initialize the auth module:
260
+ ### Security: Restrict Redirect Paths
206
261
 
207
262
  ```typescript
208
263
  createAuth({
209
- baseURL: string // Required: Your API endpoint
264
+ baseURL: 'https://api.example.com',
265
+ redirect: {
266
+ allowedPaths: [
267
+ /^\/dashboard/,
268
+ /^\/profile/,
269
+ /^\/settings/,
270
+ ],
271
+ // Only these paths can be redirect targets
272
+ }
210
273
  })
211
274
  ```
212
275
 
213
- ### `createAuthRoutes(config)`
276
+ ### Disable Auto-Redirect
214
277
 
215
- Create auth routes for Vue Router:
278
+ For custom logic:
216
279
 
217
280
  ```typescript
218
- createAuthRoutes({
219
- basePath?: string // Base path for routes (default: '')
220
- namePrefix?: string // Prefix for route names (default: '')
221
- routeNames?: { // Custom route names
222
- login?: string
223
- signup?: string
224
- forgotPassword?: string
225
- resetPassword?: string
226
- callback?: string
281
+ createAuth({
282
+ redirect: {
283
+ autoRedirect: false, // Manual control
227
284
  }
228
- redirectTo?: string // Redirect after auth (default: '/')
229
- layout?: Component // Wrapper layout component
230
285
  })
231
- ```
232
286
 
233
- ### `createAuthGuard(config)`
287
+ // Then in login handler:
288
+ import { performRedirect, getRedirectConfig } from '@bagelink/auth'
234
289
 
235
- Create a navigation guard:
290
+ await auth.login(credentials)
291
+ await performRedirect(router, getRedirectConfig())
292
+ ```
293
+
294
+ ### Custom Route Meta Key
236
295
 
237
296
  ```typescript
238
- createAuthGuard({
239
- redirectTo?: string // Where to redirect authenticated users (default: '/')
297
+ createAuth({
298
+ redirect: {
299
+ authMetaKey: 'requiresAuth', // Default: 'auth'
300
+ }
240
301
  })
302
+
303
+ // Then in routes:
304
+ {
305
+ path: '/dashboard',
306
+ meta: { requiresAuth: true } // Custom meta key
307
+ }
241
308
  ```
242
309
 
243
- ## Customization
310
+ ## Event System
244
311
 
245
- ### Text Customization
312
+ Listen to auth events:
246
313
 
247
- All forms support custom text via the `texts` prop:
314
+ ```typescript
315
+ import { createAuth, AuthState } from '@bagelink/auth'
248
316
 
249
- ```vue
250
- <LoginForm
251
- :texts="{
252
- title: 'Sign In',
253
- emailLabel: 'Email Address',
254
- passwordLabel: 'Password',
255
- loginButton: 'Continue',
256
- githubButton: 'Continue with GitHub'
257
- }"
258
- />
259
- ```
317
+ const auth = createAuth({ ... })
260
318
 
261
- ### Multi-language Support
319
+ auth.on(AuthState.LOGIN, () => {
320
+ console.log('User logged in')
321
+ })
262
322
 
263
- ```vue
264
- <script setup>
265
- import { ref, computed } from 'vue'
266
- import { LoginForm } from '@bagelink/auth'
267
-
268
- const locale = ref('en')
269
-
270
- const texts = computed(() => {
271
- if (locale.value === 'he') {
272
- return {
273
- title: 'התחברות',
274
- emailLabel: 'אימייל',
275
- passwordLabel: 'סיסמה',
276
- loginButton: 'התחברות'
277
- }
278
- }
279
- return {
280
- title: 'Login',
281
- emailLabel: 'Email',
282
- passwordLabel: 'Password',
283
- loginButton: 'Login'
284
- }
323
+ auth.on(AuthState.LOGOUT, () => {
324
+ console.log('User logged out')
285
325
  })
286
- </script>
287
326
 
288
- <template>
289
- <LoginForm :texts="texts" />
290
- </template>
327
+ auth.on(AuthState.PROFILE_UPDATE, () => {
328
+ console.log('Profile updated')
329
+ })
291
330
  ```
292
331
 
293
- ### Custom Layout
294
-
295
- Create a layout wrapper:
332
+ Available events:
333
+ - `LOGIN`
334
+ - `LOGOUT`
335
+ - `SIGNUP`
336
+ - `PASSWORD_RESET`
337
+ - `PASSWORD_CHANGE`
338
+ - `PROFILE_UPDATE`
339
+ - `AUTH_CHECK`
340
+ - `EMAIL_VERIFIED`
341
+ - `SESSION_REFRESH`
296
342
 
297
- ```vue
298
- <!-- AuthLayout.vue -->
299
- <template>
300
- <div class="auth-layout">
301
- <header>
302
- <img src="/logo.png" alt="Logo">
303
- </header>
304
- <main>
305
- <router-view />
306
- </main>
307
- <footer>
308
- © 2024 Your Company
309
- </footer>
310
- </div>
311
- </template>
312
- ```
343
+ ## TypeScript Support
313
344
 
314
- Then use it:
345
+ Full type definitions included:
315
346
 
316
347
  ```typescript
317
- import AuthLayout from './AuthLayout.vue'
318
-
319
- createAuthRoutes({
320
- layout: AuthLayout
321
- })
348
+ import type {
349
+ User,
350
+ AccountInfo,
351
+ AuthState,
352
+ SSOProvider,
353
+ RedirectConfig,
354
+ LoginTexts,
355
+ SignupTexts,
356
+ } from '@bagelink/auth'
322
357
  ```
323
358
 
324
- ## Advanced Usage
359
+ ## Examples
325
360
 
326
- ### Protected Routes
361
+ ### Protected Route Flow
327
362
 
328
- ```typescript
329
- router.beforeEach(async (to, from, next) => {
330
- const { isAuthenticated } = useAuth()
331
-
332
- if (to.meta.requiresAuth && !isAuthenticated.value) {
333
- next('/login')
334
- } else {
335
- next()
336
- }
337
- })
338
- ```
363
+ 1. User visits `/dashboard` (protected)
364
+ 2. Not authenticated redirected to `/login?redirect=/dashboard`
365
+ 3. User logs in
366
+ 4. Auto-redirected to `/dashboard`
339
367
 
340
- ### Programmatic Navigation
368
+ ### Custom Login Page
341
369
 
342
- ```typescript
343
- import { useRouter } from 'vue-router'
370
+ ```vue
371
+ <script setup lang="ts">
372
+ import { ref } from 'vue'
344
373
  import { useAuth } from '@bagelink/auth'
345
374
 
346
- const router = useRouter()
347
- const { login } = useAuth()
375
+ const auth = useAuth()
376
+ const email = ref('')
377
+ const password = ref('')
378
+ const error = ref('')
348
379
 
349
380
  async function handleLogin() {
350
381
  try {
351
- await login(email, password)
352
- router.push('/dashboard')
353
- } catch (error) {
354
- console.error('Login failed:', error)
382
+ await auth.login({ email: email.value, password: password.value })
383
+ // Auto-redirect happens automatically!
384
+ } catch (err: any) {
385
+ error.value = err.response?.data?.message || 'Login failed'
355
386
  }
356
387
  }
388
+ </script>
389
+
390
+ <template>
391
+ <form @submit.prevent="handleLogin">
392
+ <input v-model="email" type="email" placeholder="Email" />
393
+ <input v-model="password" type="password" placeholder="Password" />
394
+ <button type="submit">Login</button>
395
+ <p v-if="error" class="error">{{ error }}</p>
396
+ </form>
397
+ </template>
357
398
  ```
358
399
 
359
- ### Custom Error Handling
400
+ ### Role-Based Access
360
401
 
361
402
  ```typescript
362
- const { login } = useAuth()
363
-
364
- try {
365
- await login(email, password)
366
- } catch (error) {
367
- if (error.code === 'INVALID_CREDENTIALS') {
368
- // Handle invalid credentials
369
- } else if (error.code === 'NETWORK_ERROR') {
370
- // Handle network error
371
- }
372
- }
373
- ```
403
+ import { useAuth } from '@bagelink/auth'
374
404
 
375
- ## TypeScript Support
405
+ const auth = useAuth()
376
406
 
377
- Full TypeScript support with exported types:
407
+ // Check if user has admin role
408
+ if (auth.getRoles().includes('admin')) {
409
+ // Allow access
410
+ }
378
411
 
379
- ```typescript
380
- import type {
381
- AuthState,
382
- User,
383
- AccountInfo,
384
- SSOProvider,
385
- LoginTexts,
386
- SignupTexts,
387
- AuthRouteConfig
388
- } from '@bagelink/auth'
412
+ // Or in route guard
413
+ router.beforeEach((to, from, next) => {
414
+ if (to.meta.requiresAdmin && !auth.getRoles().includes('admin')) {
415
+ next('/unauthorized')
416
+ } else {
417
+ next()
418
+ }
419
+ })
389
420
  ```
390
421
 
422
+ ## Migration
423
+
424
+ See [BREAKING_CHANGES.md](./BREAKING_CHANGES.md) for migration guide from previous versions.
425
+
391
426
  ## License
392
427
 
393
428
  MIT