@hamak/auth 0.5.1

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 (116) hide show
  1. package/README.md +366 -0
  2. package/dist/api/api/auth-service.d.ts +111 -0
  3. package/dist/api/api/auth-service.d.ts.map +1 -0
  4. package/dist/api/api/auth-service.js +5 -0
  5. package/dist/api/api/index.d.ts +2 -0
  6. package/dist/api/api/index.d.ts.map +1 -0
  7. package/dist/api/api/index.js +1 -0
  8. package/dist/api/index.d.ts +10 -0
  9. package/dist/api/index.d.ts.map +1 -0
  10. package/dist/api/index.js +12 -0
  11. package/dist/api/tokens/index.d.ts +2 -0
  12. package/dist/api/tokens/index.d.ts.map +1 -0
  13. package/dist/api/tokens/index.js +1 -0
  14. package/dist/api/tokens/service-tokens.d.ts +26 -0
  15. package/dist/api/tokens/service-tokens.d.ts.map +1 -0
  16. package/dist/api/tokens/service-tokens.js +25 -0
  17. package/dist/api/types/auth-result.d.ts +69 -0
  18. package/dist/api/types/auth-result.d.ts.map +1 -0
  19. package/dist/api/types/auth-result.js +5 -0
  20. package/dist/api/types/config.d.ts +130 -0
  21. package/dist/api/types/config.d.ts.map +1 -0
  22. package/dist/api/types/config.js +5 -0
  23. package/dist/api/types/credentials.d.ts +52 -0
  24. package/dist/api/types/credentials.d.ts.map +1 -0
  25. package/dist/api/types/credentials.js +5 -0
  26. package/dist/api/types/index.d.ts +5 -0
  27. package/dist/api/types/index.d.ts.map +1 -0
  28. package/dist/api/types/index.js +4 -0
  29. package/dist/api/types/user.d.ts +39 -0
  30. package/dist/api/types/user.d.ts.map +1 -0
  31. package/dist/api/types/user.js +5 -0
  32. package/dist/impl/index.d.ts +15 -0
  33. package/dist/impl/index.d.ts.map +1 -0
  34. package/dist/impl/index.js +21 -0
  35. package/dist/impl/plugin/auth-plugin-factory.d.ts +20 -0
  36. package/dist/impl/plugin/auth-plugin-factory.d.ts.map +1 -0
  37. package/dist/impl/plugin/auth-plugin-factory.js +226 -0
  38. package/dist/impl/plugin/index.d.ts +2 -0
  39. package/dist/impl/plugin/index.d.ts.map +1 -0
  40. package/dist/impl/plugin/index.js +1 -0
  41. package/dist/impl/services/AuthService.d.ts +44 -0
  42. package/dist/impl/services/AuthService.d.ts.map +1 -0
  43. package/dist/impl/services/AuthService.js +277 -0
  44. package/dist/impl/services/index.d.ts +2 -0
  45. package/dist/impl/services/index.d.ts.map +1 -0
  46. package/dist/impl/services/index.js +1 -0
  47. package/dist/impl/storage/LocalTokenStorage.d.ts +32 -0
  48. package/dist/impl/storage/LocalTokenStorage.d.ts.map +1 -0
  49. package/dist/impl/storage/LocalTokenStorage.js +148 -0
  50. package/dist/impl/storage/MemoryTokenStorage.d.ts +34 -0
  51. package/dist/impl/storage/MemoryTokenStorage.d.ts.map +1 -0
  52. package/dist/impl/storage/MemoryTokenStorage.js +91 -0
  53. package/dist/impl/storage/SessionTokenStorage.d.ts +33 -0
  54. package/dist/impl/storage/SessionTokenStorage.d.ts.map +1 -0
  55. package/dist/impl/storage/SessionTokenStorage.js +147 -0
  56. package/dist/impl/storage/index.d.ts +10 -0
  57. package/dist/impl/storage/index.d.ts.map +1 -0
  58. package/dist/impl/storage/index.js +26 -0
  59. package/dist/impl/store/auth-reducer.d.ts +135 -0
  60. package/dist/impl/store/auth-reducer.d.ts.map +1 -0
  61. package/dist/impl/store/auth-reducer.js +179 -0
  62. package/dist/impl/store/index.d.ts +2 -0
  63. package/dist/impl/store/index.d.ts.map +1 -0
  64. package/dist/impl/store/index.js +1 -0
  65. package/dist/impl/strategies/KeycloakStrategy.d.ts +42 -0
  66. package/dist/impl/strategies/KeycloakStrategy.d.ts.map +1 -0
  67. package/dist/impl/strategies/KeycloakStrategy.js +237 -0
  68. package/dist/impl/strategies/OAuth2Strategy.d.ts +30 -0
  69. package/dist/impl/strategies/OAuth2Strategy.d.ts.map +1 -0
  70. package/dist/impl/strategies/OAuth2Strategy.js +232 -0
  71. package/dist/impl/strategies/PasswordStrategy.d.ts +25 -0
  72. package/dist/impl/strategies/PasswordStrategy.d.ts.map +1 -0
  73. package/dist/impl/strategies/PasswordStrategy.js +159 -0
  74. package/dist/impl/strategies/StrategyRegistry.d.ts +24 -0
  75. package/dist/impl/strategies/StrategyRegistry.d.ts.map +1 -0
  76. package/dist/impl/strategies/StrategyRegistry.js +70 -0
  77. package/dist/impl/strategies/index.d.ts +5 -0
  78. package/dist/impl/strategies/index.d.ts.map +1 -0
  79. package/dist/impl/strategies/index.js +4 -0
  80. package/dist/impl/utils/index.d.ts +3 -0
  81. package/dist/impl/utils/index.d.ts.map +1 -0
  82. package/dist/impl/utils/index.js +2 -0
  83. package/dist/impl/utils/jwt.d.ts +81 -0
  84. package/dist/impl/utils/jwt.d.ts.map +1 -0
  85. package/dist/impl/utils/jwt.js +103 -0
  86. package/dist/impl/utils/pkce.d.ts +44 -0
  87. package/dist/impl/utils/pkce.d.ts.map +1 -0
  88. package/dist/impl/utils/pkce.js +93 -0
  89. package/dist/index.d.ts +12 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +11 -0
  92. package/dist/spi/guards/AuthGuard.d.ts +108 -0
  93. package/dist/spi/guards/AuthGuard.d.ts.map +1 -0
  94. package/dist/spi/guards/AuthGuard.js +5 -0
  95. package/dist/spi/guards/index.d.ts +2 -0
  96. package/dist/spi/guards/index.d.ts.map +1 -0
  97. package/dist/spi/guards/index.js +1 -0
  98. package/dist/spi/index.d.ts +12 -0
  99. package/dist/spi/index.d.ts.map +1 -0
  100. package/dist/spi/index.js +15 -0
  101. package/dist/spi/storage/ITokenStorage.d.ts +107 -0
  102. package/dist/spi/storage/ITokenStorage.d.ts.map +1 -0
  103. package/dist/spi/storage/ITokenStorage.js +5 -0
  104. package/dist/spi/storage/index.d.ts +2 -0
  105. package/dist/spi/storage/index.d.ts.map +1 -0
  106. package/dist/spi/storage/index.js +1 -0
  107. package/dist/spi/strategies/IAuthStrategy.d.ts +114 -0
  108. package/dist/spi/strategies/IAuthStrategy.d.ts.map +1 -0
  109. package/dist/spi/strategies/IAuthStrategy.js +16 -0
  110. package/dist/spi/strategies/IStrategyRegistry.d.ts +64 -0
  111. package/dist/spi/strategies/IStrategyRegistry.d.ts.map +1 -0
  112. package/dist/spi/strategies/IStrategyRegistry.js +5 -0
  113. package/dist/spi/strategies/index.d.ts +3 -0
  114. package/dist/spi/strategies/index.d.ts.map +1 -0
  115. package/dist/spi/strategies/index.js +2 -0
  116. package/package.json +78 -0
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Strategy Registry Implementation
3
+ * Registry for managing multiple authentication strategies
4
+ */
5
+ import type { IAuthStrategy, IOAuthStrategy, IStrategyRegistry } from '../../spi';
6
+ /**
7
+ * Default implementation of the strategy registry
8
+ */
9
+ export declare class StrategyRegistry implements IStrategyRegistry {
10
+ private strategies;
11
+ private defaultStrategyName;
12
+ register(strategy: IAuthStrategy): void;
13
+ unregister(name: string): void;
14
+ get(name: string): IAuthStrategy | undefined;
15
+ getOAuth(name: string): IOAuthStrategy | undefined;
16
+ getAll(): IAuthStrategy[];
17
+ getAllOAuth(): IOAuthStrategy[];
18
+ has(name: string): boolean;
19
+ getDefault(): IAuthStrategy | undefined;
20
+ setDefault(name: string): void;
21
+ clear(): void;
22
+ private isOAuthStrategy;
23
+ }
24
+ //# sourceMappingURL=StrategyRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StrategyRegistry.d.ts","sourceRoot":"","sources":["../../../src/impl/strategies/StrategyRegistry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAElF;;GAEG;AACH,qBAAa,gBAAiB,YAAW,iBAAiB;IACxD,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,mBAAmB,CAAuB;IAElD,QAAQ,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAYvC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAW9B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI5C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAQlD,MAAM,IAAI,aAAa,EAAE;IAIzB,WAAW,IAAI,cAAc,EAAE;IAI/B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,UAAU,IAAI,aAAa,GAAG,SAAS;IAOvC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAO9B,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,eAAe;CAGxB"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Strategy Registry Implementation
3
+ * Registry for managing multiple authentication strategies
4
+ */
5
+ /**
6
+ * Default implementation of the strategy registry
7
+ */
8
+ export class StrategyRegistry {
9
+ constructor() {
10
+ this.strategies = new Map();
11
+ this.defaultStrategyName = null;
12
+ }
13
+ register(strategy) {
14
+ if (this.strategies.has(strategy.name)) {
15
+ console.warn(`Strategy "${strategy.name}" is already registered. Overwriting.`);
16
+ }
17
+ this.strategies.set(strategy.name, strategy);
18
+ // Set as default if it's the first strategy
19
+ if (this.strategies.size === 1) {
20
+ this.defaultStrategyName = strategy.name;
21
+ }
22
+ }
23
+ unregister(name) {
24
+ this.strategies.delete(name);
25
+ // Clear default if it was the unregistered strategy
26
+ if (this.defaultStrategyName === name) {
27
+ this.defaultStrategyName = this.strategies.size > 0
28
+ ? this.strategies.keys().next().value ?? null
29
+ : null;
30
+ }
31
+ }
32
+ get(name) {
33
+ return this.strategies.get(name);
34
+ }
35
+ getOAuth(name) {
36
+ const strategy = this.strategies.get(name);
37
+ if (strategy && this.isOAuthStrategy(strategy)) {
38
+ return strategy;
39
+ }
40
+ return undefined;
41
+ }
42
+ getAll() {
43
+ return Array.from(this.strategies.values());
44
+ }
45
+ getAllOAuth() {
46
+ return this.getAll().filter(this.isOAuthStrategy);
47
+ }
48
+ has(name) {
49
+ return this.strategies.has(name);
50
+ }
51
+ getDefault() {
52
+ if (!this.defaultStrategyName) {
53
+ return undefined;
54
+ }
55
+ return this.strategies.get(this.defaultStrategyName);
56
+ }
57
+ setDefault(name) {
58
+ if (!this.strategies.has(name)) {
59
+ throw new Error(`Strategy "${name}" is not registered`);
60
+ }
61
+ this.defaultStrategyName = name;
62
+ }
63
+ clear() {
64
+ this.strategies.clear();
65
+ this.defaultStrategyName = null;
66
+ }
67
+ isOAuthStrategy(strategy) {
68
+ return 'getAuthorizationUrl' in strategy && 'handleCallback' in strategy;
69
+ }
70
+ }
@@ -0,0 +1,5 @@
1
+ export * from './PasswordStrategy';
2
+ export * from './OAuth2Strategy';
3
+ export * from './KeycloakStrategy';
4
+ export * from './StrategyRegistry';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/impl/strategies/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './PasswordStrategy';
2
+ export * from './OAuth2Strategy';
3
+ export * from './KeycloakStrategy';
4
+ export * from './StrategyRegistry';
@@ -0,0 +1,3 @@
1
+ export * from './pkce';
2
+ export * from './jwt';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/impl/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './pkce';
2
+ export * from './jwt';
@@ -0,0 +1,81 @@
1
+ /**
2
+ * JWT Utilities
3
+ * Utilities for parsing and validating JWT tokens
4
+ */
5
+ import type { User } from '../../api';
6
+ /**
7
+ * Standard JWT payload claims
8
+ */
9
+ export interface JWTPayload {
10
+ /** Subject (user ID) */
11
+ sub?: string;
12
+ /** Email */
13
+ email?: string;
14
+ /** Name */
15
+ name?: string;
16
+ /** Preferred username */
17
+ preferred_username?: string;
18
+ /** Given name */
19
+ given_name?: string;
20
+ /** Family name */
21
+ family_name?: string;
22
+ /** Picture/avatar URL */
23
+ picture?: string;
24
+ /** Issued at (timestamp) */
25
+ iat?: number;
26
+ /** Expiration time (timestamp) */
27
+ exp?: number;
28
+ /** Not before (timestamp) */
29
+ nbf?: number;
30
+ /** Issuer */
31
+ iss?: string;
32
+ /** Audience */
33
+ aud?: string | string[];
34
+ /** JWT ID */
35
+ jti?: string;
36
+ /** Scopes */
37
+ scope?: string;
38
+ /** Keycloak realm access */
39
+ realm_access?: {
40
+ roles: string[];
41
+ };
42
+ /** Keycloak resource access */
43
+ resource_access?: Record<string, {
44
+ roles: string[];
45
+ }>;
46
+ /** Custom claims */
47
+ [key: string]: unknown;
48
+ }
49
+ /**
50
+ * Parse a JWT token and extract the payload
51
+ * Note: This does NOT validate the signature
52
+ * @param token The JWT token string
53
+ * @returns The decoded payload or null if invalid
54
+ */
55
+ export declare function parseJWT(token: string): JWTPayload | null;
56
+ /**
57
+ * Check if a JWT token is expired
58
+ * @param token The JWT token or parsed payload
59
+ * @param bufferSeconds Extra seconds before expiry to consider expired (default: 0)
60
+ */
61
+ export declare function isJWTExpired(token: string | JWTPayload, bufferSeconds?: number): boolean;
62
+ /**
63
+ * Get expiration time from a JWT token
64
+ * @param token The JWT token
65
+ * @returns Expiration timestamp in milliseconds or null
66
+ */
67
+ export declare function getJWTExpiry(token: string): number | null;
68
+ /**
69
+ * Extract user information from a JWT token
70
+ * Handles standard OIDC claims and Keycloak-specific claims
71
+ * @param token The JWT token
72
+ * @param clientId Optional client ID for Keycloak resource roles
73
+ */
74
+ export declare function extractUserFromJWT(token: string, clientId?: string): User | null;
75
+ /**
76
+ * Calculate time until token expires
77
+ * @param token The JWT token
78
+ * @returns Time in milliseconds until expiry, or 0 if expired
79
+ */
80
+ export declare function getTimeUntilExpiry(token: string): number;
81
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../src/impl/utils/jwt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yBAAyB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe;IACf,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,aAAa;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,YAAY,CAAC,EAAE;QACb,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;IACF,+BAA+B;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACtD,oBAAoB;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAqBzD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,aAAa,SAAI,GAAG,OAAO,CAQnF;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMzD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAkChF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMxD"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * JWT Utilities
3
+ * Utilities for parsing and validating JWT tokens
4
+ */
5
+ /**
6
+ * Parse a JWT token and extract the payload
7
+ * Note: This does NOT validate the signature
8
+ * @param token The JWT token string
9
+ * @returns The decoded payload or null if invalid
10
+ */
11
+ export function parseJWT(token) {
12
+ try {
13
+ const parts = token.split('.');
14
+ if (parts.length !== 3) {
15
+ return null;
16
+ }
17
+ const payload = parts[1];
18
+ // Handle base64url encoding
19
+ const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
20
+ const jsonPayload = decodeURIComponent(atob(base64)
21
+ .split('')
22
+ .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
23
+ .join(''));
24
+ return JSON.parse(jsonPayload);
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ /**
31
+ * Check if a JWT token is expired
32
+ * @param token The JWT token or parsed payload
33
+ * @param bufferSeconds Extra seconds before expiry to consider expired (default: 0)
34
+ */
35
+ export function isJWTExpired(token, bufferSeconds = 0) {
36
+ const payload = typeof token === 'string' ? parseJWT(token) : token;
37
+ if (!payload?.exp) {
38
+ return true;
39
+ }
40
+ const now = Math.floor(Date.now() / 1000);
41
+ return payload.exp - bufferSeconds <= now;
42
+ }
43
+ /**
44
+ * Get expiration time from a JWT token
45
+ * @param token The JWT token
46
+ * @returns Expiration timestamp in milliseconds or null
47
+ */
48
+ export function getJWTExpiry(token) {
49
+ const payload = parseJWT(token);
50
+ if (!payload?.exp) {
51
+ return null;
52
+ }
53
+ return payload.exp * 1000;
54
+ }
55
+ /**
56
+ * Extract user information from a JWT token
57
+ * Handles standard OIDC claims and Keycloak-specific claims
58
+ * @param token The JWT token
59
+ * @param clientId Optional client ID for Keycloak resource roles
60
+ */
61
+ export function extractUserFromJWT(token, clientId) {
62
+ const payload = parseJWT(token);
63
+ if (!payload) {
64
+ return null;
65
+ }
66
+ // Extract roles from Keycloak format
67
+ const realmRoles = payload.realm_access?.roles || [];
68
+ const resourceRoles = clientId
69
+ ? payload.resource_access?.[clientId]?.roles || []
70
+ : [];
71
+ const roles = [...new Set([...realmRoles, ...resourceRoles])];
72
+ // Extract permissions (scopes)
73
+ const permissions = payload.scope?.split(' ').filter(Boolean) || [];
74
+ // Build user object
75
+ const user = {
76
+ id: payload.sub || '',
77
+ email: payload.email || '',
78
+ name: payload.name || payload.preferred_username || '',
79
+ username: payload.preferred_username,
80
+ avatar: payload.picture,
81
+ roles,
82
+ permissions,
83
+ metadata: {
84
+ iss: payload.iss,
85
+ aud: payload.aud,
86
+ iat: payload.iat,
87
+ exp: payload.exp
88
+ }
89
+ };
90
+ return user;
91
+ }
92
+ /**
93
+ * Calculate time until token expires
94
+ * @param token The JWT token
95
+ * @returns Time in milliseconds until expiry, or 0 if expired
96
+ */
97
+ export function getTimeUntilExpiry(token) {
98
+ const expiry = getJWTExpiry(token);
99
+ if (!expiry) {
100
+ return 0;
101
+ }
102
+ return Math.max(0, expiry - Date.now());
103
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * PKCE (Proof Key for Code Exchange) Utilities
3
+ * Used for secure OAuth2 authorization code flow
4
+ */
5
+ /**
6
+ * Generate a cryptographically random string for state or code verifier
7
+ * @param length Length of the string (default: 43 for code verifier)
8
+ */
9
+ export declare function generateRandomString(length?: number): string;
10
+ /**
11
+ * Generate a state parameter for OAuth
12
+ */
13
+ export declare function generateState(): string;
14
+ /**
15
+ * Generate a code verifier for PKCE
16
+ * Must be between 43 and 128 characters
17
+ */
18
+ export declare function generateCodeVerifier(): string;
19
+ /**
20
+ * Generate a code challenge from a code verifier
21
+ * Uses SHA-256 hashing as recommended by RFC 7636
22
+ */
23
+ export declare function generateCodeChallenge(verifier: string): Promise<string>;
24
+ /**
25
+ * PKCE state stored during OAuth flow
26
+ */
27
+ export interface PKCEState {
28
+ state: string;
29
+ codeVerifier: string;
30
+ createdAt: number;
31
+ }
32
+ /**
33
+ * Store PKCE state for later verification
34
+ */
35
+ export declare function storePKCEState(pkceState: PKCEState): void;
36
+ /**
37
+ * Retrieve stored PKCE state
38
+ */
39
+ export declare function retrievePKCEState(): PKCEState | null;
40
+ /**
41
+ * Clear stored PKCE state
42
+ */
43
+ export declare function clearPKCEState(): void;
44
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../../src/impl/utils/pkce.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,SAAK,GAAG,MAAM,CAIxD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAK7E;AAiBD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAOzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,SAAS,GAAG,IAAI,CAWpD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAMrC"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * PKCE (Proof Key for Code Exchange) Utilities
3
+ * Used for secure OAuth2 authorization code flow
4
+ */
5
+ /**
6
+ * Generate a cryptographically random string for state or code verifier
7
+ * @param length Length of the string (default: 43 for code verifier)
8
+ */
9
+ export function generateRandomString(length = 43) {
10
+ const array = new Uint8Array(length);
11
+ crypto.getRandomValues(array);
12
+ return base64UrlEncode(array);
13
+ }
14
+ /**
15
+ * Generate a state parameter for OAuth
16
+ */
17
+ export function generateState() {
18
+ return generateRandomString(32);
19
+ }
20
+ /**
21
+ * Generate a code verifier for PKCE
22
+ * Must be between 43 and 128 characters
23
+ */
24
+ export function generateCodeVerifier() {
25
+ return generateRandomString(43);
26
+ }
27
+ /**
28
+ * Generate a code challenge from a code verifier
29
+ * Uses SHA-256 hashing as recommended by RFC 7636
30
+ */
31
+ export async function generateCodeChallenge(verifier) {
32
+ const encoder = new TextEncoder();
33
+ const data = encoder.encode(verifier);
34
+ const hash = await crypto.subtle.digest('SHA-256', data);
35
+ return base64UrlEncode(new Uint8Array(hash));
36
+ }
37
+ /**
38
+ * Base64 URL encode a byte array
39
+ * Uses URL-safe alphabet without padding as per RFC 4648
40
+ */
41
+ function base64UrlEncode(buffer) {
42
+ let binary = '';
43
+ for (let i = 0; i < buffer.length; i++) {
44
+ binary += String.fromCharCode(buffer[i]);
45
+ }
46
+ return btoa(binary)
47
+ .replace(/\+/g, '-')
48
+ .replace(/\//g, '_')
49
+ .replace(/=/g, '');
50
+ }
51
+ /**
52
+ * Storage key for PKCE state
53
+ */
54
+ const PKCE_STORAGE_KEY = '@hamak/auth:pkce';
55
+ /**
56
+ * Store PKCE state for later verification
57
+ */
58
+ export function storePKCEState(pkceState) {
59
+ try {
60
+ sessionStorage.setItem(PKCE_STORAGE_KEY, JSON.stringify(pkceState));
61
+ }
62
+ catch {
63
+ // Fallback to memory if sessionStorage is not available
64
+ window[PKCE_STORAGE_KEY] = pkceState;
65
+ }
66
+ }
67
+ /**
68
+ * Retrieve stored PKCE state
69
+ */
70
+ export function retrievePKCEState() {
71
+ try {
72
+ const stored = sessionStorage.getItem(PKCE_STORAGE_KEY);
73
+ if (stored) {
74
+ return JSON.parse(stored);
75
+ }
76
+ }
77
+ catch {
78
+ // Fallback to memory
79
+ return window[PKCE_STORAGE_KEY] || null;
80
+ }
81
+ return null;
82
+ }
83
+ /**
84
+ * Clear stored PKCE state
85
+ */
86
+ export function clearPKCEState() {
87
+ try {
88
+ sessionStorage.removeItem(PKCE_STORAGE_KEY);
89
+ }
90
+ catch {
91
+ delete window[PKCE_STORAGE_KEY];
92
+ }
93
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @hamak/auth
3
+ *
4
+ * Complete authentication plugin with password, OAuth2, and Keycloak support.
5
+ *
6
+ * Usage:
7
+ * import { createAuthPlugin, AUTH_SERVICE_TOKEN } from '@hamak/auth';
8
+ * import type { IAuthService } from '@hamak/auth/api';
9
+ * import type { ITokenStorage } from '@hamak/auth/spi';
10
+ */
11
+ export * from './impl';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,cAAc,QAAQ,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @hamak/auth
3
+ *
4
+ * Complete authentication plugin with password, OAuth2, and Keycloak support.
5
+ *
6
+ * Usage:
7
+ * import { createAuthPlugin, AUTH_SERVICE_TOKEN } from '@hamak/auth';
8
+ * import type { IAuthService } from '@hamak/auth/api';
9
+ * import type { ITokenStorage } from '@hamak/auth/spi';
10
+ */
11
+ export * from './impl';
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Auth Guard Interface
3
+ * Navigation guards for protected routes
4
+ */
5
+ import type { IAuthService, User } from '../../api';
6
+ /**
7
+ * Route metadata that can be used for auth decisions
8
+ */
9
+ export interface RouteMeta {
10
+ /** Whether the route requires authentication */
11
+ requiresAuth?: boolean;
12
+ /** Required roles to access the route */
13
+ roles?: string[];
14
+ /** Required permissions to access the route */
15
+ permissions?: string[];
16
+ /** Custom guard function */
17
+ guard?: (user: User | null) => boolean;
18
+ /** Path to redirect to if auth fails */
19
+ redirectTo?: string;
20
+ }
21
+ /**
22
+ * Guard context passed to auth guards
23
+ */
24
+ export interface AuthGuardContext {
25
+ /** The path being navigated to */
26
+ toPath: string;
27
+ /** The path being navigated from */
28
+ fromPath: string | null;
29
+ /** Route metadata */
30
+ meta?: RouteMeta;
31
+ /** The auth service instance */
32
+ authService: IAuthService;
33
+ /** Abort navigation */
34
+ abort: () => void;
35
+ /** Redirect to a different path */
36
+ redirect: (path: string) => void;
37
+ /** Continue with navigation */
38
+ proceed: () => void;
39
+ }
40
+ /**
41
+ * Auth guard function type
42
+ */
43
+ export type AuthGuardFn = (context: AuthGuardContext) => void | Promise<void>;
44
+ /**
45
+ * Auth guard configuration
46
+ */
47
+ export interface AuthGuardConfig {
48
+ /** Path to redirect unauthenticated users */
49
+ loginPath: string;
50
+ /** Path to redirect unauthorized users (has auth but wrong permissions) */
51
+ unauthorizedPath?: string;
52
+ /** Path to redirect after successful login */
53
+ afterLoginPath?: string;
54
+ /** Whether to store the intended path for redirect after login */
55
+ preserveIntendedPath?: boolean;
56
+ /** Key to use when storing intended path */
57
+ intendedPathKey?: string;
58
+ }
59
+ /**
60
+ * Auth guard manager interface
61
+ * Manages navigation guards for authentication
62
+ */
63
+ export interface IAuthGuardManager {
64
+ /**
65
+ * Register a global auth guard
66
+ * @param guard The guard function
67
+ * @returns Unregister function
68
+ */
69
+ register(guard: AuthGuardFn): () => void;
70
+ /**
71
+ * Check if navigation to a path is allowed
72
+ * @param context The guard context
73
+ * @returns Whether navigation should proceed
74
+ */
75
+ check(context: AuthGuardContext): Promise<boolean>;
76
+ /**
77
+ * Create a guard that requires authentication
78
+ * @param config Guard configuration
79
+ */
80
+ requireAuth(config?: Partial<AuthGuardConfig>): AuthGuardFn;
81
+ /**
82
+ * Create a guard that requires specific roles
83
+ * @param roles Required roles (user must have at least one)
84
+ * @param config Guard configuration
85
+ */
86
+ requireRoles(roles: string[], config?: Partial<AuthGuardConfig>): AuthGuardFn;
87
+ /**
88
+ * Create a guard that requires specific permissions
89
+ * @param permissions Required permissions (user must have all)
90
+ * @param config Guard configuration
91
+ */
92
+ requirePermissions(permissions: string[], config?: Partial<AuthGuardConfig>): AuthGuardFn;
93
+ /**
94
+ * Store the intended path for redirect after login
95
+ * @param path The path the user intended to visit
96
+ */
97
+ setIntendedPath(path: string): void;
98
+ /**
99
+ * Get and clear the intended path
100
+ * @returns The intended path or null
101
+ */
102
+ getIntendedPath(): string | null;
103
+ /**
104
+ * Clear all registered guards
105
+ */
106
+ clear(): void;
107
+ }
108
+ //# sourceMappingURL=AuthGuard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthGuard.d.ts","sourceRoot":"","sources":["../../../src/spi/guards/AuthGuard.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,gDAAgD;IAChD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC;IACvC,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,qBAAqB;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,gCAAgC;IAChC,WAAW,EAAE,YAAY,CAAC;IAC1B,uBAAuB;IACvB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,mCAAmC;IACnC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,+BAA+B;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,IAAI,CAAC;IAEzC;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEnD;;;OAGG;IACH,WAAW,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,WAAW,CAAC;IAE5D;;;;OAIG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,WAAW,CAAC;IAE9E;;;;OAIG;IACH,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,WAAW,CAAC;IAE1F;;;OAGG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpC;;;OAGG;IACH,eAAe,IAAI,MAAM,GAAG,IAAI,CAAC;IAEjC;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;CACf"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Auth Guard Interface
3
+ * Navigation guards for protected routes
4
+ */
5
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './AuthGuard';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/spi/guards/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
@@ -0,0 +1 @@
1
+ export * from './AuthGuard';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @hamak/auth/spi
3
+ *
4
+ * Service Provider Interfaces for the authentication system.
5
+ * Contains extension points for implementing custom strategies,
6
+ * storage providers, and guards.
7
+ */
8
+ export * from '../api';
9
+ export * from './strategies';
10
+ export * from './storage';
11
+ export * from './guards';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/spi/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,cAAc,QAAQ,CAAC;AAGvB,cAAc,cAAc,CAAC;AAG7B,cAAc,WAAW,CAAC;AAG1B,cAAc,UAAU,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @hamak/auth/spi
3
+ *
4
+ * Service Provider Interfaces for the authentication system.
5
+ * Contains extension points for implementing custom strategies,
6
+ * storage providers, and guards.
7
+ */
8
+ // Re-export API types for convenience
9
+ export * from '../api';
10
+ // Strategy interfaces
11
+ export * from './strategies';
12
+ // Storage interfaces
13
+ export * from './storage';
14
+ // Guard interfaces
15
+ export * from './guards';