auth-gate 0.2.3__tar.gz → 0.3.0__tar.gz

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 (29) hide show
  1. {auth_gate-0.2.3/src/auth_gate.egg-info → auth_gate-0.3.0}/PKG-INFO +167 -18
  2. {auth_gate-0.2.3 → auth_gate-0.3.0}/README.md +165 -16
  3. {auth_gate-0.2.3 → auth_gate-0.3.0}/pyproject.toml +2 -2
  4. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate/__init__.py +58 -4
  5. auth_gate-0.3.0/src/auth_gate/exceptions.py +58 -0
  6. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate/fastapi_utils.py +264 -2
  7. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate/middleware.py +6 -1
  8. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate/schemas.py +56 -1
  9. auth_gate-0.3.0/src/auth_gate/subscription.py +126 -0
  10. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate/user_auth.py +47 -0
  11. {auth_gate-0.2.3 → auth_gate-0.3.0/src/auth_gate.egg-info}/PKG-INFO +167 -18
  12. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate.egg-info/SOURCES.txt +3 -0
  13. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/tests/conftest.py +111 -0
  14. auth_gate-0.3.0/src/tests/test_subscription.py +237 -0
  15. {auth_gate-0.2.3 → auth_gate-0.3.0}/LICENSE +0 -0
  16. {auth_gate-0.2.3 → auth_gate-0.3.0}/setup.cfg +0 -0
  17. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate/config.py +0 -0
  18. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate/s2s_auth.py +0 -0
  19. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate.egg-info/dependency_links.txt +0 -0
  20. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate.egg-info/requires.txt +0 -0
  21. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/auth_gate.egg-info/top_level.txt +0 -0
  22. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/tests/__init__.py +0 -0
  23. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/tests/test_config.py +0 -0
  24. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/tests/test_fastapi_utils.py +0 -0
  25. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/tests/test_intergration.py +0 -0
  26. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/tests/test_middleware.py +0 -0
  27. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/tests/test_s2s_auth.py +0 -0
  28. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/tests/test_schema.py +0 -0
  29. {auth_gate-0.2.3 → auth_gate-0.3.0}/src/tests/test_user_auth.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: auth-gate
3
- Version: 0.2.3
4
- Summary: Enterprise-grade authentication for microservices with Kong and Keycloak integration
3
+ Version: 0.3.0
4
+ Summary: Enterprise-grade authentication for microservices with Kong/Keycloak integration and subscription tier support
5
5
  Home-page: https://github.com/tradelink-org/auth-gate
6
6
  Author: Brian Mburu
7
7
  Author-email: Brian Mburu <brian.mburu@students.jkuat.ac.ke>
@@ -41,12 +41,13 @@ Dynamic: license-file
41
41
 
42
42
  # Auth Gate
43
43
 
44
- Enterprise-grade authentication for microservices with Kong and Keycloak integration, supporting both user and service-to-service authentication.
44
+ Enterprise-grade authentication for microservices with Kong and Keycloak integration, supporting user authentication, service-to-service authentication, and subscription tier enforcement.
45
45
 
46
46
  ## Features
47
47
 
48
48
  - **Dual authentication types**: Support for both user authentication and service-to-service authentication
49
49
  - **Unified authentication flow**: Single middleware handles both user and service tokens seamlessly
50
+ - **Subscription tier enforcement**: Built-in support for FREE, BASIC, PROFESSIONAL, and ENTERPRISE tiers
50
51
  - **Flexible endpoint protection**: Configure endpoints as user-only, service-only, or accessible by both
51
52
  - **Dual-mode authentication**: Support for both Kong header-based auth (production) and direct Keycloak validation (development)
52
53
  - **Service-to-service authentication**: Built-in client credentials flow for secure inter-service communication
@@ -55,6 +56,7 @@ Enterprise-grade authentication for microservices with Kong and Keycloak integra
55
56
  - **FastAPI integration**: Ready-to-use dependencies for protecting endpoints
56
57
  - **Role-based access control**: Fine-grained permission management with role and scope validation for both users and services
57
58
  - **Middleware support**: Automatic request authentication with configurable exclusions
59
+ - **Organization context**: Multi-tenant support with organization ID tracking
58
60
 
59
61
  ## Installation
60
62
 
@@ -136,6 +138,44 @@ async def get_data(auth: AuthContext = Depends(get_current_auth)):
136
138
  return {"data": "full", "service": auth.service_name}
137
139
  ```
138
140
 
141
+ ### Subscription Tier Enforcement
142
+
143
+ ```python
144
+ from auth_gate import (
145
+ require_tier,
146
+ require_tier_and_active,
147
+ require_basic,
148
+ require_professional,
149
+ require_enterprise,
150
+ require_paid_subscription,
151
+ SubscriptionTier,
152
+ )
153
+
154
+ # Require minimum tier (PROFESSIONAL or higher)
155
+ @app.get("/api/analytics/advanced")
156
+ async def get_advanced_analytics(
157
+ auth: AuthContext = Depends(require_tier(SubscriptionTier.PROFESSIONAL))
158
+ ):
159
+ return {"data": "advanced analytics"}
160
+
161
+ # Convenience dependency for common tiers
162
+ @app.get("/api/reports/enterprise")
163
+ async def get_enterprise_reports(auth: AuthContext = Depends(require_enterprise)):
164
+ return {"reports": [...]}
165
+
166
+ # Require both minimum tier AND active subscription
167
+ @app.get("/api/premium/dashboard")
168
+ async def get_premium_dashboard(
169
+ auth: AuthContext = Depends(require_tier_and_active(SubscriptionTier.BASIC))
170
+ ):
171
+ return {"dashboard": "premium data"}
172
+
173
+ # Require any paid subscription (non-free)
174
+ @app.get("/api/paid-feature")
175
+ async def get_paid_feature(auth: AuthContext = Depends(require_paid_subscription)):
176
+ return {"feature": "paid-only data"}
177
+ ```
178
+
139
179
  ### Role-Based Access Control
140
180
 
141
181
  ```python
@@ -214,6 +254,16 @@ VERIFY_HMAC=false
214
254
  INTERNAL_HMAC_KEY=your-hmac-key
215
255
  ```
216
256
 
257
+ ### Kong Headers for Subscription
258
+
259
+ When using Kong, configure the Token Introspector plugin to inject these subscription headers:
260
+
261
+ | Header | Description | Example Values |
262
+ | ----------------------- | ------------------------------ | --------------------------------------- |
263
+ | `X-Subscription-Tier` | User's subscription tier | `free`, `basic`, `professional`, `enterprise` |
264
+ | `X-Subscription-Status` | Subscription status | `active`, `suspended`, `cancelled`, `past_due` |
265
+ | `X-Organization-ID` | Organization identifier | `org-12345` |
266
+
217
267
  ## Service-to-Service Authentication
218
268
 
219
269
  ### Making Service Calls
@@ -379,14 +429,17 @@ The S2S auth client includes automatic circuit breaker protection:
379
429
 
380
430
  ```python
381
431
  class UserContext:
382
- user_id: str # Unique user identifier
383
- username: str | None # Username
384
- email: str | None # Email address
385
- roles: List[str] # User roles
386
- scopes: List[str] # OAuth scopes
387
- session_id: str | None # Session identifier
388
- client_id: str | None # OAuth client ID
389
- auth_source: str # Authentication source
432
+ user_id: str # Unique user identifier
433
+ username: str | None # Username
434
+ email: str | None # Email address
435
+ roles: List[str] # User roles
436
+ scopes: List[str] # OAuth scopes
437
+ session_id: str | None # Session identifier
438
+ client_id: str | None # OAuth client ID
439
+ auth_source: str # Authentication source
440
+ organization_id: str | None # Organization identifier
441
+ subscription_tier: SubscriptionTier # Subscription tier (FREE, BASIC, PROFESSIONAL, ENTERPRISE)
442
+ subscription_status: SubscriptionStatus # Status (ACTIVE, SUSPENDED, CANCELLED, PAST_DUE)
390
443
 
391
444
  # Properties
392
445
  is_service: bool # Always False for users
@@ -394,6 +447,9 @@ class UserContext:
394
447
  is_supplier: bool # True if has supplier role
395
448
  is_customer: bool # True if has customer role
396
449
  is_moderator: bool # True if has moderator role
450
+ is_buyer: bool # True if has buyer or customer role
451
+ is_subscription_active: bool # True if subscription status is ACTIVE
452
+ is_paid_subscriber: bool # True if tier is not FREE
397
453
 
398
454
  # Methods
399
455
  has_role(role: str) -> bool
@@ -401,18 +457,23 @@ class UserContext:
401
457
  has_all_roles(roles: List[str]) -> bool
402
458
  has_scope(scope: str) -> bool
403
459
  has_any_scope(scopes: List[str]) -> bool
460
+ has_minimum_tier(required_tier: SubscriptionTier) -> bool
461
+ can_access_feature(required_tier: SubscriptionTier) -> bool
404
462
  ```
405
463
 
406
464
  ### ServiceContext
407
465
 
408
466
  ```python
409
467
  class ServiceContext:
410
- service_name: str # Service identifier (client_id)
411
- service_id: str | None # Service sub claim
412
- roles: List[str] # Service roles
413
- session_id: str | None # Session identifier
414
- client_id: str | None # OAuth client ID
415
- auth_source: str # Authentication source
468
+ service_name: str # Service identifier (client_id)
469
+ service_id: str | None # Service sub claim
470
+ roles: List[str] # Service roles
471
+ session_id: str | None # Session identifier
472
+ client_id: str | None # OAuth client ID
473
+ auth_source: str # Authentication source
474
+ organization_id: str | None # Organization identifier
475
+ subscription_tier: SubscriptionTier # Defaults to FREE (services bypass tier checks)
476
+ subscription_status: SubscriptionStatus # Defaults to ACTIVE
416
477
 
417
478
  # Properties
418
479
  is_service: bool # Always True for services
@@ -424,6 +485,8 @@ class ServiceContext:
424
485
  has_all_roles(roles: List[str]) -> bool
425
486
  ```
426
487
 
488
+ **Note:** Services bypass subscription tier checks by default when using `require_tier()` and related dependencies.
489
+
427
490
  ## Available Dependencies
428
491
 
429
492
  ### Authentication Dependencies
@@ -462,6 +525,59 @@ require_service_roles("role1", "role2", ...)
462
525
  require_scopes("scope1", "scope2", ...)
463
526
  ```
464
527
 
528
+ ### Subscription Dependencies
529
+
530
+ | Dependency | Description |
531
+ | ----------------------------- | --------------------------------------------------- |
532
+ | `require_tier(tier)` | Factory requiring minimum subscription tier |
533
+ | `require_active_subscription()` | Factory requiring active subscription status |
534
+ | `require_tier_and_active(tier)` | Factory requiring both tier and active status |
535
+ | `require_basic` | Requires BASIC tier or higher |
536
+ | `require_professional` | Requires PROFESSIONAL tier or higher |
537
+ | `require_enterprise` | Requires ENTERPRISE tier |
538
+ | `require_paid_subscription` | Requires any paid tier (non-FREE) |
539
+ | `get_subscription_tier` | Extract tier from header |
540
+ | `get_organization_id` | Extract organization ID from header |
541
+
542
+ ### Subscription Types
543
+
544
+ ```python
545
+ from auth_gate import SubscriptionTier, SubscriptionStatus
546
+
547
+ # Tier hierarchy (lowest to highest)
548
+ SubscriptionTier.FREE
549
+ SubscriptionTier.BASIC
550
+ SubscriptionTier.PROFESSIONAL
551
+ SubscriptionTier.ENTERPRISE
552
+
553
+ # Subscription statuses
554
+ SubscriptionStatus.ACTIVE
555
+ SubscriptionStatus.SUSPENDED
556
+ SubscriptionStatus.CANCELLED
557
+ SubscriptionStatus.PAST_DUE
558
+ ```
559
+
560
+ ### Subscription Utilities
561
+
562
+ ```python
563
+ from auth_gate import (
564
+ meets_minimum_tier,
565
+ compare_tiers,
566
+ is_paid_tier,
567
+ get_tier_level,
568
+ )
569
+
570
+ # Check if user tier meets requirement
571
+ meets_minimum_tier(SubscriptionTier.PROFESSIONAL, SubscriptionTier.BASIC) # True
572
+
573
+ # Compare tiers (-1, 0, 1)
574
+ compare_tiers(SubscriptionTier.ENTERPRISE, SubscriptionTier.FREE) # > 0
575
+
576
+ # Check if tier is paid
577
+ is_paid_tier(SubscriptionTier.BASIC) # True
578
+ is_paid_tier(SubscriptionTier.FREE) # False
579
+ ```
580
+
465
581
  ## Migration Guide
466
582
 
467
583
  ### Updating Existing Applications
@@ -529,11 +645,15 @@ from auth_gate import (
529
645
  AuthContext,
530
646
  UserContext,
531
647
  ServiceContext,
648
+ SubscriptionTier,
532
649
  get_current_auth,
533
650
  get_current_user,
534
651
  get_current_service,
535
652
  require_roles,
536
653
  require_user_roles,
654
+ require_tier,
655
+ require_tier_and_active,
656
+ require_professional,
537
657
  )
538
658
 
539
659
  app = FastAPI()
@@ -552,7 +672,11 @@ async def health():
552
672
  # User-only endpoint
553
673
  @app.get("/api/user/profile")
554
674
  async def get_profile(user: UserContext = Depends(get_current_user)):
555
- return {"user": user.user_id}
675
+ return {
676
+ "user": user.user_id,
677
+ "tier": user.subscription_tier.value,
678
+ "organization": user.organization_id
679
+ }
556
680
 
557
681
  # Service-only endpoint
558
682
  @app.post("/api/internal/batch")
@@ -573,6 +697,31 @@ require_user_editor = require_user_roles("editor")
573
697
  @app.post("/api/articles")
574
698
  async def create_article(user: UserContext = Depends(require_user_editor)):
575
699
  return {"author": user.user_id}
700
+
701
+ # Tier-protected endpoint (PROFESSIONAL or higher)
702
+ @app.get("/api/analytics")
703
+ async def get_analytics(auth: AuthContext = Depends(require_professional)):
704
+ return {"analytics": "professional data"}
705
+
706
+ # Tier and active subscription required
707
+ @app.get("/api/premium/reports")
708
+ async def get_premium_reports(
709
+ auth: AuthContext = Depends(require_tier_and_active(SubscriptionTier.BASIC))
710
+ ):
711
+ return {"reports": "premium data"}
712
+
713
+ # Custom tier check within endpoint
714
+ @app.get("/api/features")
715
+ async def get_features(user: UserContext = Depends(get_current_user)):
716
+ features = ["basic_dashboard"]
717
+
718
+ if user.has_minimum_tier(SubscriptionTier.PROFESSIONAL):
719
+ features.append("advanced_analytics")
720
+
721
+ if user.has_minimum_tier(SubscriptionTier.ENTERPRISE):
722
+ features.append("custom_integrations")
723
+
724
+ return {"features": features, "tier": user.subscription_tier.value}
576
725
  ```
577
726
 
578
727
  ## License
@@ -1,11 +1,12 @@
1
1
  # Auth Gate
2
2
 
3
- Enterprise-grade authentication for microservices with Kong and Keycloak integration, supporting both user and service-to-service authentication.
3
+ Enterprise-grade authentication for microservices with Kong and Keycloak integration, supporting user authentication, service-to-service authentication, and subscription tier enforcement.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - **Dual authentication types**: Support for both user authentication and service-to-service authentication
8
8
  - **Unified authentication flow**: Single middleware handles both user and service tokens seamlessly
9
+ - **Subscription tier enforcement**: Built-in support for FREE, BASIC, PROFESSIONAL, and ENTERPRISE tiers
9
10
  - **Flexible endpoint protection**: Configure endpoints as user-only, service-only, or accessible by both
10
11
  - **Dual-mode authentication**: Support for both Kong header-based auth (production) and direct Keycloak validation (development)
11
12
  - **Service-to-service authentication**: Built-in client credentials flow for secure inter-service communication
@@ -14,6 +15,7 @@ Enterprise-grade authentication for microservices with Kong and Keycloak integra
14
15
  - **FastAPI integration**: Ready-to-use dependencies for protecting endpoints
15
16
  - **Role-based access control**: Fine-grained permission management with role and scope validation for both users and services
16
17
  - **Middleware support**: Automatic request authentication with configurable exclusions
18
+ - **Organization context**: Multi-tenant support with organization ID tracking
17
19
 
18
20
  ## Installation
19
21
 
@@ -95,6 +97,44 @@ async def get_data(auth: AuthContext = Depends(get_current_auth)):
95
97
  return {"data": "full", "service": auth.service_name}
96
98
  ```
97
99
 
100
+ ### Subscription Tier Enforcement
101
+
102
+ ```python
103
+ from auth_gate import (
104
+ require_tier,
105
+ require_tier_and_active,
106
+ require_basic,
107
+ require_professional,
108
+ require_enterprise,
109
+ require_paid_subscription,
110
+ SubscriptionTier,
111
+ )
112
+
113
+ # Require minimum tier (PROFESSIONAL or higher)
114
+ @app.get("/api/analytics/advanced")
115
+ async def get_advanced_analytics(
116
+ auth: AuthContext = Depends(require_tier(SubscriptionTier.PROFESSIONAL))
117
+ ):
118
+ return {"data": "advanced analytics"}
119
+
120
+ # Convenience dependency for common tiers
121
+ @app.get("/api/reports/enterprise")
122
+ async def get_enterprise_reports(auth: AuthContext = Depends(require_enterprise)):
123
+ return {"reports": [...]}
124
+
125
+ # Require both minimum tier AND active subscription
126
+ @app.get("/api/premium/dashboard")
127
+ async def get_premium_dashboard(
128
+ auth: AuthContext = Depends(require_tier_and_active(SubscriptionTier.BASIC))
129
+ ):
130
+ return {"dashboard": "premium data"}
131
+
132
+ # Require any paid subscription (non-free)
133
+ @app.get("/api/paid-feature")
134
+ async def get_paid_feature(auth: AuthContext = Depends(require_paid_subscription)):
135
+ return {"feature": "paid-only data"}
136
+ ```
137
+
98
138
  ### Role-Based Access Control
99
139
 
100
140
  ```python
@@ -173,6 +213,16 @@ VERIFY_HMAC=false
173
213
  INTERNAL_HMAC_KEY=your-hmac-key
174
214
  ```
175
215
 
216
+ ### Kong Headers for Subscription
217
+
218
+ When using Kong, configure the Token Introspector plugin to inject these subscription headers:
219
+
220
+ | Header | Description | Example Values |
221
+ | ----------------------- | ------------------------------ | --------------------------------------- |
222
+ | `X-Subscription-Tier` | User's subscription tier | `free`, `basic`, `professional`, `enterprise` |
223
+ | `X-Subscription-Status` | Subscription status | `active`, `suspended`, `cancelled`, `past_due` |
224
+ | `X-Organization-ID` | Organization identifier | `org-12345` |
225
+
176
226
  ## Service-to-Service Authentication
177
227
 
178
228
  ### Making Service Calls
@@ -338,14 +388,17 @@ The S2S auth client includes automatic circuit breaker protection:
338
388
 
339
389
  ```python
340
390
  class UserContext:
341
- user_id: str # Unique user identifier
342
- username: str | None # Username
343
- email: str | None # Email address
344
- roles: List[str] # User roles
345
- scopes: List[str] # OAuth scopes
346
- session_id: str | None # Session identifier
347
- client_id: str | None # OAuth client ID
348
- auth_source: str # Authentication source
391
+ user_id: str # Unique user identifier
392
+ username: str | None # Username
393
+ email: str | None # Email address
394
+ roles: List[str] # User roles
395
+ scopes: List[str] # OAuth scopes
396
+ session_id: str | None # Session identifier
397
+ client_id: str | None # OAuth client ID
398
+ auth_source: str # Authentication source
399
+ organization_id: str | None # Organization identifier
400
+ subscription_tier: SubscriptionTier # Subscription tier (FREE, BASIC, PROFESSIONAL, ENTERPRISE)
401
+ subscription_status: SubscriptionStatus # Status (ACTIVE, SUSPENDED, CANCELLED, PAST_DUE)
349
402
 
350
403
  # Properties
351
404
  is_service: bool # Always False for users
@@ -353,6 +406,9 @@ class UserContext:
353
406
  is_supplier: bool # True if has supplier role
354
407
  is_customer: bool # True if has customer role
355
408
  is_moderator: bool # True if has moderator role
409
+ is_buyer: bool # True if has buyer or customer role
410
+ is_subscription_active: bool # True if subscription status is ACTIVE
411
+ is_paid_subscriber: bool # True if tier is not FREE
356
412
 
357
413
  # Methods
358
414
  has_role(role: str) -> bool
@@ -360,18 +416,23 @@ class UserContext:
360
416
  has_all_roles(roles: List[str]) -> bool
361
417
  has_scope(scope: str) -> bool
362
418
  has_any_scope(scopes: List[str]) -> bool
419
+ has_minimum_tier(required_tier: SubscriptionTier) -> bool
420
+ can_access_feature(required_tier: SubscriptionTier) -> bool
363
421
  ```
364
422
 
365
423
  ### ServiceContext
366
424
 
367
425
  ```python
368
426
  class ServiceContext:
369
- service_name: str # Service identifier (client_id)
370
- service_id: str | None # Service sub claim
371
- roles: List[str] # Service roles
372
- session_id: str | None # Session identifier
373
- client_id: str | None # OAuth client ID
374
- auth_source: str # Authentication source
427
+ service_name: str # Service identifier (client_id)
428
+ service_id: str | None # Service sub claim
429
+ roles: List[str] # Service roles
430
+ session_id: str | None # Session identifier
431
+ client_id: str | None # OAuth client ID
432
+ auth_source: str # Authentication source
433
+ organization_id: str | None # Organization identifier
434
+ subscription_tier: SubscriptionTier # Defaults to FREE (services bypass tier checks)
435
+ subscription_status: SubscriptionStatus # Defaults to ACTIVE
375
436
 
376
437
  # Properties
377
438
  is_service: bool # Always True for services
@@ -383,6 +444,8 @@ class ServiceContext:
383
444
  has_all_roles(roles: List[str]) -> bool
384
445
  ```
385
446
 
447
+ **Note:** Services bypass subscription tier checks by default when using `require_tier()` and related dependencies.
448
+
386
449
  ## Available Dependencies
387
450
 
388
451
  ### Authentication Dependencies
@@ -421,6 +484,59 @@ require_service_roles("role1", "role2", ...)
421
484
  require_scopes("scope1", "scope2", ...)
422
485
  ```
423
486
 
487
+ ### Subscription Dependencies
488
+
489
+ | Dependency | Description |
490
+ | ----------------------------- | --------------------------------------------------- |
491
+ | `require_tier(tier)` | Factory requiring minimum subscription tier |
492
+ | `require_active_subscription()` | Factory requiring active subscription status |
493
+ | `require_tier_and_active(tier)` | Factory requiring both tier and active status |
494
+ | `require_basic` | Requires BASIC tier or higher |
495
+ | `require_professional` | Requires PROFESSIONAL tier or higher |
496
+ | `require_enterprise` | Requires ENTERPRISE tier |
497
+ | `require_paid_subscription` | Requires any paid tier (non-FREE) |
498
+ | `get_subscription_tier` | Extract tier from header |
499
+ | `get_organization_id` | Extract organization ID from header |
500
+
501
+ ### Subscription Types
502
+
503
+ ```python
504
+ from auth_gate import SubscriptionTier, SubscriptionStatus
505
+
506
+ # Tier hierarchy (lowest to highest)
507
+ SubscriptionTier.FREE
508
+ SubscriptionTier.BASIC
509
+ SubscriptionTier.PROFESSIONAL
510
+ SubscriptionTier.ENTERPRISE
511
+
512
+ # Subscription statuses
513
+ SubscriptionStatus.ACTIVE
514
+ SubscriptionStatus.SUSPENDED
515
+ SubscriptionStatus.CANCELLED
516
+ SubscriptionStatus.PAST_DUE
517
+ ```
518
+
519
+ ### Subscription Utilities
520
+
521
+ ```python
522
+ from auth_gate import (
523
+ meets_minimum_tier,
524
+ compare_tiers,
525
+ is_paid_tier,
526
+ get_tier_level,
527
+ )
528
+
529
+ # Check if user tier meets requirement
530
+ meets_minimum_tier(SubscriptionTier.PROFESSIONAL, SubscriptionTier.BASIC) # True
531
+
532
+ # Compare tiers (-1, 0, 1)
533
+ compare_tiers(SubscriptionTier.ENTERPRISE, SubscriptionTier.FREE) # > 0
534
+
535
+ # Check if tier is paid
536
+ is_paid_tier(SubscriptionTier.BASIC) # True
537
+ is_paid_tier(SubscriptionTier.FREE) # False
538
+ ```
539
+
424
540
  ## Migration Guide
425
541
 
426
542
  ### Updating Existing Applications
@@ -488,11 +604,15 @@ from auth_gate import (
488
604
  AuthContext,
489
605
  UserContext,
490
606
  ServiceContext,
607
+ SubscriptionTier,
491
608
  get_current_auth,
492
609
  get_current_user,
493
610
  get_current_service,
494
611
  require_roles,
495
612
  require_user_roles,
613
+ require_tier,
614
+ require_tier_and_active,
615
+ require_professional,
496
616
  )
497
617
 
498
618
  app = FastAPI()
@@ -511,7 +631,11 @@ async def health():
511
631
  # User-only endpoint
512
632
  @app.get("/api/user/profile")
513
633
  async def get_profile(user: UserContext = Depends(get_current_user)):
514
- return {"user": user.user_id}
634
+ return {
635
+ "user": user.user_id,
636
+ "tier": user.subscription_tier.value,
637
+ "organization": user.organization_id
638
+ }
515
639
 
516
640
  # Service-only endpoint
517
641
  @app.post("/api/internal/batch")
@@ -532,6 +656,31 @@ require_user_editor = require_user_roles("editor")
532
656
  @app.post("/api/articles")
533
657
  async def create_article(user: UserContext = Depends(require_user_editor)):
534
658
  return {"author": user.user_id}
659
+
660
+ # Tier-protected endpoint (PROFESSIONAL or higher)
661
+ @app.get("/api/analytics")
662
+ async def get_analytics(auth: AuthContext = Depends(require_professional)):
663
+ return {"analytics": "professional data"}
664
+
665
+ # Tier and active subscription required
666
+ @app.get("/api/premium/reports")
667
+ async def get_premium_reports(
668
+ auth: AuthContext = Depends(require_tier_and_active(SubscriptionTier.BASIC))
669
+ ):
670
+ return {"reports": "premium data"}
671
+
672
+ # Custom tier check within endpoint
673
+ @app.get("/api/features")
674
+ async def get_features(user: UserContext = Depends(get_current_user)):
675
+ features = ["basic_dashboard"]
676
+
677
+ if user.has_minimum_tier(SubscriptionTier.PROFESSIONAL):
678
+ features.append("advanced_analytics")
679
+
680
+ if user.has_minimum_tier(SubscriptionTier.ENTERPRISE):
681
+ features.append("custom_integrations")
682
+
683
+ return {"features": features, "tier": user.subscription_tier.value}
535
684
  ```
536
685
 
537
686
  ## License
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "auth-gate"
7
- version = "0.2.3"
8
- description = "Enterprise-grade authentication for microservices with Kong and Keycloak integration"
7
+ version = "0.3.0"
8
+ description = "Enterprise-grade authentication for microservices with Kong/Keycloak integration and subscription tier support"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
11
11
  license = {text = "MIT"}