@tideorg/mcp 1.4.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.
Files changed (76) hide show
  1. package/GAP_REGISTER.md +117 -0
  2. package/README.md +38 -0
  3. package/adapters/AGENTS.md +241 -0
  4. package/adapters/CLAUDE.md +146 -0
  5. package/adapters/replit.md +224 -0
  6. package/canon/anti-patterns.md +2133 -0
  7. package/canon/concepts.md +816 -0
  8. package/canon/custom-contracts.md +533 -0
  9. package/canon/delegation.md +195 -0
  10. package/canon/feature-mapping.md +637 -0
  11. package/canon/framework-matrix.md +1125 -0
  12. package/canon/invariants.md +851 -0
  13. package/canon/redirect-handler.md +254 -0
  14. package/canon/tidecloak-bootstrap.md +287 -0
  15. package/canon/tidecloak-endpoints.md +294 -0
  16. package/canon/troubleshooting.md +1494 -0
  17. package/canon/version-policy.md +89 -0
  18. package/mcp-server/dist/index.d.ts +2 -0
  19. package/mcp-server/dist/index.js +605 -0
  20. package/package.json +45 -0
  21. package/playbooks/add-auth-nextjs-existing.md +799 -0
  22. package/playbooks/add-auth-nextjs-fresh.md +654 -0
  23. package/playbooks/add-rbac-nextjs.md +190 -0
  24. package/playbooks/bootstrap-realm-from-template.md +170 -0
  25. package/playbooks/configure-e2ee-roles-and-policies.md +196 -0
  26. package/playbooks/deploy-tidecloak-docker.md +792 -0
  27. package/playbooks/diagnose-broken-login.md +234 -0
  28. package/playbooks/diagnose-missing-roles-or-claims.md +253 -0
  29. package/playbooks/initialize-admin-and-link-account.md +235 -0
  30. package/playbooks/migrate-from-existing-auth.md +198 -0
  31. package/playbooks/protect-api-nextjs.md +451 -0
  32. package/playbooks/protect-routes-nextjs.md +544 -0
  33. package/playbooks/setup-forseti-e2ee.md +756 -0
  34. package/playbooks/setup-iga-admin-panel.md +344 -0
  35. package/playbooks/setup-server-delegation.md +142 -0
  36. package/playbooks/start-tidecloak-dev.md +130 -0
  37. package/playbooks/verify-jwt-server-side.md +439 -0
  38. package/prompts/add-admin-approval-flow.md +50 -0
  39. package/prompts/build-private-customer-portal.md +85 -0
  40. package/prompts/migrate-generic-auth-to-tide.md +67 -0
  41. package/prompts/secure-existing-app.md +80 -0
  42. package/reference-apps/INDEX.md +87 -0
  43. package/reference-apps/encrypted-communication/anti-patterns.md +123 -0
  44. package/reference-apps/encrypted-communication/bootstrap-sequence.md +152 -0
  45. package/reference-apps/encrypted-communication/manifest.yaml +100 -0
  46. package/reference-apps/encrypted-communication/role-policy-matrix.md +80 -0
  47. package/reference-apps/encrypted-communication/scenario.md +134 -0
  48. package/reference-apps/git-pr-signing-service/anti-patterns.md +61 -0
  49. package/reference-apps/git-pr-signing-service/bootstrap-sequence.md +157 -0
  50. package/reference-apps/git-pr-signing-service/manifest.yaml +80 -0
  51. package/reference-apps/git-pr-signing-service/role-policy-matrix.md +99 -0
  52. package/reference-apps/git-pr-signing-service/scenario.md +169 -0
  53. package/reference-apps/iga-admin-governance/anti-patterns.md +133 -0
  54. package/reference-apps/iga-admin-governance/bootstrap-sequence.md +153 -0
  55. package/reference-apps/iga-admin-governance/manifest.yaml +87 -0
  56. package/reference-apps/iga-admin-governance/role-policy-matrix.md +67 -0
  57. package/reference-apps/iga-admin-governance/scenario.md +126 -0
  58. package/reference-apps/organisation-password-manager/anti-patterns.md +71 -0
  59. package/reference-apps/organisation-password-manager/bootstrap-sequence.md +127 -0
  60. package/reference-apps/organisation-password-manager/manifest.yaml +86 -0
  61. package/reference-apps/organisation-password-manager/role-policy-matrix.md +59 -0
  62. package/reference-apps/organisation-password-manager/scenario.md +107 -0
  63. package/reference-apps/policy-governed-signing/anti-patterns.md +67 -0
  64. package/reference-apps/policy-governed-signing/bootstrap-sequence.md +128 -0
  65. package/reference-apps/policy-governed-signing/manifest.yaml +78 -0
  66. package/reference-apps/policy-governed-signing/role-policy-matrix.md +62 -0
  67. package/reference-apps/policy-governed-signing/scenario.md +113 -0
  68. package/skills/tide-diagnostics/SKILL.md +99 -0
  69. package/skills/tide-integration/SKILL.md +136 -0
  70. package/skills/tide-learning-capture/SKILL.md +174 -0
  71. package/skills/tide-rbac-and-e2ee/SKILL.md +214 -0
  72. package/skills/tide-reviewer/SKILL.md +133 -0
  73. package/skills/tide-route-and-api-protection/SKILL.md +201 -0
  74. package/skills/tide-scenario-resolver/SKILL.md +81 -0
  75. package/skills/tide-setup/SKILL.md +218 -0
  76. package/skills/tide-solutions-architect/SKILL.md +130 -0
@@ -0,0 +1,544 @@
1
+ # Protect Routes in Next.js (Client-Side UI Gating)
2
+
3
+ Implement client-side route guards that redirect unauthenticated users to login.
4
+
5
+ **CRITICAL**: This is UI gating only, NOT real authorization. Protected routes can be bypassed. For API protection, see [protect-api-nextjs.md](protect-api-nextjs.md).
6
+
7
+ ---
8
+
9
+ ## When to Use
10
+
11
+ - Want to hide pages from unauthenticated users (UX improvement)
12
+ - Want to redirect to login if user not authenticated
13
+ - Want to show different UI based on authentication status
14
+
15
+ **Do not use** for:
16
+ - Protecting sensitive APIs (use server-side JWT verification)
17
+ - Preventing unauthorized access to data (use server-side checks)
18
+ - Security enforcement (route guards are UI convenience only)
19
+
20
+ ---
21
+
22
+ ## Prerequisites
23
+
24
+ - Tide authentication installed ([add-auth-nextjs-fresh.md](add-auth-nextjs-fresh.md))
25
+ - `TideCloakProvider` wrapping app
26
+ - Login flow working
27
+
28
+ ---
29
+
30
+ ## Security Warning
31
+
32
+ **Route protection is NOT authorization.**
33
+
34
+ Client-side route guards can be bypassed:
35
+ - User disables JavaScript
36
+ - User modifies client code
37
+ - User directly calls APIs bypassing UI
38
+
39
+ **Real authorization** happens server-side with JWT verification.
40
+
41
+ See [canon/feature-mapping.md Protected Routes vs Protected APIs](../canon/feature-mapping.md#protected-routes-vs-protected-apis) for distinction.
42
+
43
+ See [canon/invariants.md I-08](../canon/invariants.md#i-08-ui-gating-is-not-authorization) for security rule.
44
+
45
+ ---
46
+
47
+ ## Files to Inspect First
48
+
49
+ ```bash
50
+ # Check router type
51
+ ls -la app/ 2>/dev/null && echo "App Router" || echo "Pages Router"
52
+
53
+ # List pages/routes to protect
54
+ find app/ pages/ -name "page.tsx" -o -name "*.tsx" 2>/dev/null | grep -v "_app\|_document\|layout"
55
+
56
+ # Check Next.js version to determine correct request interception filename
57
+ NEXT_MAJOR=$(node -e "try{console.log(require('next/package.json').version.split('.')[0])}catch{console.log('unknown')}" 2>/dev/null)
58
+ echo "Next.js major: $NEXT_MAJOR"
59
+ # 16+ → proxy.ts | 15 or earlier → middleware.ts
60
+ cat proxy.ts 2>/dev/null || cat middleware.ts 2>/dev/null
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Implementation Patterns
66
+
67
+ ### App Router: Layout-Based Guards
68
+
69
+ **When**: Protect entire section (e.g., `/dashboard/*`, `/admin/*`)
70
+
71
+ Create protected layout:
72
+
73
+ ```typescript
74
+ // app/dashboard/layout.tsx
75
+ 'use client';
76
+
77
+ import { useTideCloak } from '@tidecloak/nextjs';
78
+ import { useEffect } from 'react';
79
+
80
+ export default function DashboardLayout({
81
+ children
82
+ }: {
83
+ children: React.ReactNode
84
+ }) {
85
+ const { authenticated, isInitializing, login } = useTideCloak();
86
+
87
+ useEffect(() => {
88
+ if (!isInitializing && !authenticated) {
89
+ login();
90
+ }
91
+ }, [isInitializing, authenticated, login]);
92
+
93
+ // Block render until SDK is ready and user is authenticated
94
+ if (isInitializing || !authenticated) {
95
+ return <div>Checking authentication...</div>;
96
+ }
97
+
98
+ return <>{children}</>;
99
+ }
100
+ ```
101
+
102
+ **Why `isInitializing`**: The SDK is not ready immediately. Calling `login()` before initialization completes throws `"TideCloak client not initialized"`. Always gate on `isInitializing` before calling `login()`. See [canon/anti-patterns.md AP-28](../canon/anti-patterns.md#ap-28-calling-login-before-sdk-initialization).
103
+
104
+ All pages under `app/dashboard/` are now gated.
105
+
106
+ **Pros**: One file protects entire section
107
+ **Cons**: Shared layout means all pages share UI chrome
108
+
109
+ ---
110
+
111
+ ### App Router: Page-Level Guards
112
+
113
+ **When**: Protect individual pages, not entire section
114
+
115
+ ```typescript
116
+ // app/profile/page.tsx
117
+ 'use client';
118
+
119
+ import { useTideCloak } from '@tidecloak/nextjs';
120
+ import { useEffect } from 'react';
121
+
122
+ export default function ProfilePage() {
123
+ const { authenticated, isInitializing, getValueFromIdToken, login } = useTideCloak();
124
+
125
+ useEffect(() => {
126
+ if (!isInitializing && !authenticated) {
127
+ login();
128
+ }
129
+ }, [isInitializing, authenticated, login]);
130
+
131
+ if (isInitializing || !authenticated) {
132
+ return <div>Redirecting to login...</div>;
133
+ }
134
+
135
+ return (
136
+ <div>
137
+ <h1>Profile: {getValueFromIdToken("preferred_username")}</h1>
138
+ {/* page content */}
139
+ </div>
140
+ );
141
+ }
142
+ ```
143
+
144
+ **Pros**: Fine-grained control per page
145
+ **Cons**: Repeat guard logic in every protected page
146
+
147
+ ---
148
+
149
+ ### App Router: Reusable Guard Component
150
+
151
+ **When**: Many pages need same protection logic
152
+
153
+ Create guard component:
154
+
155
+ ```typescript
156
+ // components/AuthGuard.tsx
157
+ 'use client';
158
+
159
+ import { useTideCloak } from '@tidecloak/nextjs';
160
+ import { useEffect } from 'react';
161
+ import type { ReactNode } from 'react';
162
+
163
+ export function AuthGuard({ children }: { children: ReactNode }) {
164
+ const { authenticated, isInitializing, login } = useTideCloak();
165
+
166
+ useEffect(() => {
167
+ if (!isInitializing && !authenticated) {
168
+ login();
169
+ }
170
+ }, [isInitializing, authenticated, login]);
171
+
172
+ if (isInitializing || !authenticated) {
173
+ return <div>Redirecting to login...</div>;
174
+ }
175
+
176
+ return <>{children}</>;
177
+ }
178
+ ```
179
+
180
+ Use in pages:
181
+
182
+ ```typescript
183
+ // app/profile/page.tsx
184
+ import { AuthGuard } from '@/components/AuthGuard';
185
+
186
+ export default function ProfilePage() {
187
+ return (
188
+ <AuthGuard>
189
+ <h1>Profile</h1>
190
+ {/* page content */}
191
+ </AuthGuard>
192
+ );
193
+ }
194
+ ```
195
+
196
+ **Pros**: Reusable, consistent behavior
197
+ **Cons**: Extra component wrapper
198
+
199
+ ---
200
+
201
+ ### Pages Router: getServerSideProps Redirect
202
+
203
+ **When**: Pages Router, want server-side redirect before render
204
+
205
+ ```typescript
206
+ // pages/dashboard.tsx
207
+ import { GetServerSidePropsContext } from 'next';
208
+
209
+ export async function getServerSideProps(context: GetServerSidePropsContext) {
210
+ // Note: This checks cookies, not Tide JWT validity
211
+ // For real auth, verify JWT server-side
212
+ const hasCookie = context.req.cookies['some-auth-cookie'];
213
+
214
+ if (!hasCookie) {
215
+ return {
216
+ redirect: {
217
+ destination: '/login',
218
+ permanent: false
219
+ }
220
+ };
221
+ }
222
+
223
+ return {
224
+ props: {}
225
+ };
226
+ }
227
+
228
+ export default function DashboardPage() {
229
+ return <div>Dashboard</div>;
230
+ }
231
+ ```
232
+
233
+ **Warning**: This pattern checks cookie presence, not JWT validity. Not real authorization. Server-side JWT verification required for API protection.
234
+
235
+ ---
236
+
237
+ ### Pages Router: Client-Side Guard
238
+
239
+ ```typescript
240
+ // pages/profile.tsx
241
+ import { useTideCloak } from '@tidecloak/nextjs';
242
+ import { useEffect } from 'react';
243
+
244
+ export default function ProfilePage() {
245
+ const { authenticated, isInitializing, getValueFromIdToken, login } = useTideCloak();
246
+
247
+ useEffect(() => {
248
+ if (!isInitializing && !authenticated) {
249
+ login();
250
+ }
251
+ }, [isInitializing, authenticated, login]);
252
+
253
+ if (isInitializing || !authenticated) {
254
+ return <div>Redirecting...</div>;
255
+ }
256
+
257
+ return <div>Profile: {getValueFromIdToken("preferred_username")}</div>;
258
+ }
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Role-Based Route Guards (UI Only)
264
+
265
+ Show/hide UI elements based on roles.
266
+
267
+ **CRITICAL**: This is UI gating only. API must verify roles server-side.
268
+
269
+ ```typescript
270
+ // app/admin/page.tsx
271
+ 'use client';
272
+
273
+ import { useTideCloak } from '@tidecloak/nextjs';
274
+ import { useEffect } from 'react';
275
+
276
+ export default function AdminPage() {
277
+ const { authenticated, isInitializing, hasRealmRole, login } = useTideCloak();
278
+
279
+ useEffect(() => {
280
+ if (!isInitializing && !authenticated) {
281
+ login();
282
+ }
283
+ }, [isInitializing, authenticated, login]);
284
+
285
+ if (isInitializing || !authenticated) {
286
+ return <div>Checking authentication...</div>;
287
+ }
288
+
289
+ // UI gating: hide admin panel if user lacks role
290
+ if (!hasRealmRole('admin')) {
291
+ return (
292
+ <div>
293
+ <h1>Access Denied</h1>
294
+ <p>You do not have admin privileges.</p>
295
+ </div>
296
+ );
297
+ }
298
+
299
+ return (
300
+ <div>
301
+ <h1>Admin Panel</h1>
302
+ {/* admin content */}
303
+ </div>
304
+ );
305
+ }
306
+ ```
307
+
308
+ **Attacker can bypass**: Modify client code to skip `hasRealmRole()` check. Real protection happens in API routes.
309
+
310
+ ---
311
+
312
+ ## Verification Checklist
313
+
314
+ ### Route Protection
315
+
316
+ - [ ] Unauthenticated user redirected to Tide login
317
+ - [ ] After login, user redirected back to original URL
318
+ - [ ] Protected pages not accessible without auth
319
+ - [ ] Public pages (login, home) still accessible
320
+
321
+ ### Role-Based UI
322
+
323
+ - [ ] Admin-only UI elements hidden for non-admin users
324
+ - [ ] User sees appropriate UI for their role
325
+ - [ ] No errors when user lacks expected role
326
+
327
+ ### UX Quality
328
+
329
+ - [ ] No flash of protected content before redirect (loading state shown)
330
+ - [ ] Return URL preserved after login (user sent to page they requested)
331
+ - [ ] Consistent behavior across all protected routes
332
+
333
+ ### Security (Negative Test — requires [protect-api-nextjs.md](protect-api-nextjs.md) completed first)
334
+
335
+ - [ ] ✅ API calls from browser DevTools return 401 without valid JWT (even if route guard bypassed)
336
+ - [ ] ✅ Disabling JavaScript and accessing protected route still protected by API-level auth
337
+ - [ ] ✅ Modifying client code to skip route guard does NOT bypass API protection
338
+
339
+ **If any security checks fail**, API protection is missing or broken. Complete [protect-api-nextjs.md](protect-api-nextjs.md) first.
340
+
341
+ ---
342
+
343
+ ## Common Failures
344
+
345
+ ### Flash of Protected Content
346
+
347
+ **Symptom**: User briefly sees protected content before redirect to login.
348
+
349
+ **Cause**: Auth state checked after component renders.
350
+
351
+ **Fix**: Show loading state while checking auth:
352
+ ```typescript
353
+ if (!authenticated) {
354
+ return <div>Checking authentication...</div>;
355
+ }
356
+ ```
357
+
358
+ ---
359
+
360
+ ### Infinite Redirect Loop
361
+
362
+ **Symptom**: Page redirects to login, login redirects to page, infinite loop.
363
+
364
+ **Cause**: Login page itself has auth guard.
365
+
366
+ **Fix**: Exclude login/public pages from guards:
367
+ ```typescript
368
+ // Do NOT add guard to login page
369
+ // app/login/page.tsx
370
+ export default function LoginPage() {
371
+ // No AuthGuard here
372
+ return <div>Login</div>;
373
+ }
374
+ ```
375
+
376
+ ---
377
+
378
+ ### Return URL Lost After Login
379
+
380
+ **Symptom**: User redirected to login, but after login sent to home instead of original page.
381
+
382
+ **Cause**: Return URL not preserved.
383
+
384
+ **Fix**: Tide SDK handles this automatically via the redirect URIs configured in TideCloak and `tidecloak.json`. Verify the redirect URI in TideCloak client settings matches the app's actual URL.
385
+
386
+ ---
387
+
388
+ ### Role Check Always Fails
389
+
390
+ **Symptom**: `hasRealmRole('admin')` always returns false even for admin users.
391
+
392
+ **Cause**: Role name mismatch or role not in token.
393
+
394
+ **Fix**:
395
+ ```typescript
396
+ // Verify role name — decode the token to inspect claims
397
+ const { getValueFromToken } = useTideCloak();
398
+ const realmAccess = getValueFromToken("realm_access");
399
+ console.log('User roles:', realmAccess?.roles);
400
+ // Check if 'admin' is in the array
401
+
402
+ // Verify role assigned in TideCloak
403
+ // Admin Console → Users → {user} → Role Mappings
404
+ ```
405
+
406
+ ---
407
+
408
+ ## Repair Path
409
+
410
+ If route protection broken:
411
+
412
+ 1. **Verify auth works**:
413
+ ```typescript
414
+ // Add to protected page
415
+ const { authenticated, user } = useTideCloak();
416
+ console.log('Auth:', authenticated, 'User:', user);
417
+ // Should log: Auth: true, User: {name: "...", ...}
418
+ ```
419
+
420
+ 2. **Check provider wraps app**:
421
+ ```bash
422
+ # Verify TideCloakProvider in layout or _app
423
+ grep -r "TideCloakProvider" app/layout.tsx pages/_app.tsx
424
+ ```
425
+
426
+ 3. **Test in incognito**:
427
+ - Clear browser state may not be complete
428
+ - Incognito ensures fresh session
429
+
430
+ 4. **Verify API protection separate**:
431
+ ```bash
432
+ # Call protected API directly (bypass UI)
433
+ curl http://localhost:3000/api/admin/users
434
+ # Should return 401 even if route guard bypassed
435
+ ```
436
+
437
+ If API returns data without JWT, route guards are meaningless. Fix API protection first.
438
+
439
+ ---
440
+
441
+ ## Do Not Do This
442
+
443
+ ### ❌ Do Not Rely on Route Guards for Security
444
+
445
+ ```typescript
446
+ // ❌ WRONG: Route guard as only protection
447
+ // app/admin/page.tsx - guarded
448
+ // app/api/admin/users/route.ts - NO JWT verification
449
+
450
+ export async function GET() {
451
+ // Assumes only admins can reach this because route is guarded
452
+ return Response.json({ users: [...] });
453
+ }
454
+ ```
455
+
456
+ **Why**: Attacker calls API directly, bypassing route guard. No security.
457
+
458
+ **Correct**: Verify JWT in API. See [protect-api-nextjs.md](protect-api-nextjs.md).
459
+
460
+ ---
461
+
462
+ ### ❌ Do Not Use proxy.ts (or legacy middleware.ts) for Auth Checks
463
+
464
+ ```typescript
465
+ // ❌ WRONG: Next.js proxy/middleware checks auth
466
+ // proxy.ts (or middleware.ts in legacy projects)
467
+ import { NextResponse } from 'next/server';
468
+
469
+ export function middleware(req) {
470
+ const token = req.cookies.get('token');
471
+ if (!token) {
472
+ return NextResponse.redirect('/login');
473
+ }
474
+ }
475
+ ```
476
+
477
+ **Why**:
478
+ 1. `proxy.ts` runs on the edge, cannot verify JWT signature (no access to adapter JSON)
479
+ 2. Checks cookie presence, not JWT validity
480
+ 3. Not real authorization
481
+
482
+ **Version rule**: Next.js 16+ uses `proxy.ts`. Next.js 15 and earlier use `middleware.ts`. Check the installed version before creating or looking for this file. See [canon/framework-matrix.md](../canon/framework-matrix.md#request-interception--route-protection-ui-only).
483
+
484
+ **Correct**: Client-side route guards for UX, server-side JWT verification for security.
485
+
486
+ ---
487
+
488
+ ### ❌ Do Not Mix Auth Check with Data Fetching
489
+
490
+ ```typescript
491
+ // ❌ WRONG: Auth check in same component as data fetch
492
+ export default function DashboardPage() {
493
+ const { authenticated } = useTideCloak();
494
+ const [data, setData] = useState(null);
495
+
496
+ useEffect(() => {
497
+ fetch('/api/dashboard').then(r => r.json()).then(setData);
498
+ }, []);
499
+
500
+ if (!authenticated) {
501
+ return <div>Login required</div>;
502
+ }
503
+
504
+ return <div>{data?.message}</div>;
505
+ }
506
+ ```
507
+
508
+ **Why**: API call fires before auth check completes. API receives unauthenticated request.
509
+
510
+ **Correct**: Check auth first, then fetch:
511
+ ```typescript
512
+ useEffect(() => {
513
+ if (authenticated) {
514
+ fetch('/api/dashboard').then(r => r.json()).then(setData);
515
+ }
516
+ }, [authenticated]);
517
+ ```
518
+
519
+ Or use SDK's `secureFetch()` (if available) which adds auth headers automatically.
520
+
521
+ ---
522
+
523
+ ## Known Uncertainties
524
+
525
+ None specific to route protection. Inherits uncertainties from auth setup (CSP, DPoP, etc.). See [add-auth-nextjs-fresh.md Known Uncertainties](add-auth-nextjs-fresh.md#known-uncertainties).
526
+
527
+ ---
528
+
529
+ ## Next Steps
530
+
531
+ After route protection working:
532
+
533
+ 1. [Protect APIs](protect-api-nextjs.md) - Server-side JWT verification (REQUIRED for security). **Must complete before RBAC.**
534
+ 2. [Add RBAC](add-rbac-nextjs.md) - Role-based access control (depends on API protection)
535
+ 3. [Diagnose broken login](diagnose-broken-login.md) - If route guards fail
536
+
537
+ ---
538
+
539
+ ## References
540
+
541
+ - [canon/feature-mapping.md](../canon/feature-mapping.md#protected-routes-vs-protected-apis) - Route vs API protection
542
+ - [canon/invariants.md I-08](../canon/invariants.md#i-08-ui-gating-is-not-authorization) - UI gating is not authorization
543
+ - [canon/anti-patterns.md AP-02](../canon/anti-patterns.md#ap-02-relying-on-client-side-role-checks-for-authorization) - Client-side auth mistakes
544
+ - [protect-api-nextjs.md](protect-api-nextjs.md) - Real API protection