@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.
- package/README.md +366 -0
- package/dist/api/api/auth-service.d.ts +111 -0
- package/dist/api/api/auth-service.d.ts.map +1 -0
- package/dist/api/api/auth-service.js +5 -0
- package/dist/api/api/index.d.ts +2 -0
- package/dist/api/api/index.d.ts.map +1 -0
- package/dist/api/api/index.js +1 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +12 -0
- package/dist/api/tokens/index.d.ts +2 -0
- package/dist/api/tokens/index.d.ts.map +1 -0
- package/dist/api/tokens/index.js +1 -0
- package/dist/api/tokens/service-tokens.d.ts +26 -0
- package/dist/api/tokens/service-tokens.d.ts.map +1 -0
- package/dist/api/tokens/service-tokens.js +25 -0
- package/dist/api/types/auth-result.d.ts +69 -0
- package/dist/api/types/auth-result.d.ts.map +1 -0
- package/dist/api/types/auth-result.js +5 -0
- package/dist/api/types/config.d.ts +130 -0
- package/dist/api/types/config.d.ts.map +1 -0
- package/dist/api/types/config.js +5 -0
- package/dist/api/types/credentials.d.ts +52 -0
- package/dist/api/types/credentials.d.ts.map +1 -0
- package/dist/api/types/credentials.js +5 -0
- package/dist/api/types/index.d.ts +5 -0
- package/dist/api/types/index.d.ts.map +1 -0
- package/dist/api/types/index.js +4 -0
- package/dist/api/types/user.d.ts +39 -0
- package/dist/api/types/user.d.ts.map +1 -0
- package/dist/api/types/user.js +5 -0
- package/dist/impl/index.d.ts +15 -0
- package/dist/impl/index.d.ts.map +1 -0
- package/dist/impl/index.js +21 -0
- package/dist/impl/plugin/auth-plugin-factory.d.ts +20 -0
- package/dist/impl/plugin/auth-plugin-factory.d.ts.map +1 -0
- package/dist/impl/plugin/auth-plugin-factory.js +226 -0
- package/dist/impl/plugin/index.d.ts +2 -0
- package/dist/impl/plugin/index.d.ts.map +1 -0
- package/dist/impl/plugin/index.js +1 -0
- package/dist/impl/services/AuthService.d.ts +44 -0
- package/dist/impl/services/AuthService.d.ts.map +1 -0
- package/dist/impl/services/AuthService.js +277 -0
- package/dist/impl/services/index.d.ts +2 -0
- package/dist/impl/services/index.d.ts.map +1 -0
- package/dist/impl/services/index.js +1 -0
- package/dist/impl/storage/LocalTokenStorage.d.ts +32 -0
- package/dist/impl/storage/LocalTokenStorage.d.ts.map +1 -0
- package/dist/impl/storage/LocalTokenStorage.js +148 -0
- package/dist/impl/storage/MemoryTokenStorage.d.ts +34 -0
- package/dist/impl/storage/MemoryTokenStorage.d.ts.map +1 -0
- package/dist/impl/storage/MemoryTokenStorage.js +91 -0
- package/dist/impl/storage/SessionTokenStorage.d.ts +33 -0
- package/dist/impl/storage/SessionTokenStorage.d.ts.map +1 -0
- package/dist/impl/storage/SessionTokenStorage.js +147 -0
- package/dist/impl/storage/index.d.ts +10 -0
- package/dist/impl/storage/index.d.ts.map +1 -0
- package/dist/impl/storage/index.js +26 -0
- package/dist/impl/store/auth-reducer.d.ts +135 -0
- package/dist/impl/store/auth-reducer.d.ts.map +1 -0
- package/dist/impl/store/auth-reducer.js +179 -0
- package/dist/impl/store/index.d.ts +2 -0
- package/dist/impl/store/index.d.ts.map +1 -0
- package/dist/impl/store/index.js +1 -0
- package/dist/impl/strategies/KeycloakStrategy.d.ts +42 -0
- package/dist/impl/strategies/KeycloakStrategy.d.ts.map +1 -0
- package/dist/impl/strategies/KeycloakStrategy.js +237 -0
- package/dist/impl/strategies/OAuth2Strategy.d.ts +30 -0
- package/dist/impl/strategies/OAuth2Strategy.d.ts.map +1 -0
- package/dist/impl/strategies/OAuth2Strategy.js +232 -0
- package/dist/impl/strategies/PasswordStrategy.d.ts +25 -0
- package/dist/impl/strategies/PasswordStrategy.d.ts.map +1 -0
- package/dist/impl/strategies/PasswordStrategy.js +159 -0
- package/dist/impl/strategies/StrategyRegistry.d.ts +24 -0
- package/dist/impl/strategies/StrategyRegistry.d.ts.map +1 -0
- package/dist/impl/strategies/StrategyRegistry.js +70 -0
- package/dist/impl/strategies/index.d.ts +5 -0
- package/dist/impl/strategies/index.d.ts.map +1 -0
- package/dist/impl/strategies/index.js +4 -0
- package/dist/impl/utils/index.d.ts +3 -0
- package/dist/impl/utils/index.d.ts.map +1 -0
- package/dist/impl/utils/index.js +2 -0
- package/dist/impl/utils/jwt.d.ts +81 -0
- package/dist/impl/utils/jwt.d.ts.map +1 -0
- package/dist/impl/utils/jwt.js +103 -0
- package/dist/impl/utils/pkce.d.ts +44 -0
- package/dist/impl/utils/pkce.d.ts.map +1 -0
- package/dist/impl/utils/pkce.js +93 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/spi/guards/AuthGuard.d.ts +108 -0
- package/dist/spi/guards/AuthGuard.d.ts.map +1 -0
- package/dist/spi/guards/AuthGuard.js +5 -0
- package/dist/spi/guards/index.d.ts +2 -0
- package/dist/spi/guards/index.d.ts.map +1 -0
- package/dist/spi/guards/index.js +1 -0
- package/dist/spi/index.d.ts +12 -0
- package/dist/spi/index.d.ts.map +1 -0
- package/dist/spi/index.js +15 -0
- package/dist/spi/storage/ITokenStorage.d.ts +107 -0
- package/dist/spi/storage/ITokenStorage.d.ts.map +1 -0
- package/dist/spi/storage/ITokenStorage.js +5 -0
- package/dist/spi/storage/index.d.ts +2 -0
- package/dist/spi/storage/index.d.ts.map +1 -0
- package/dist/spi/storage/index.js +1 -0
- package/dist/spi/strategies/IAuthStrategy.d.ts +114 -0
- package/dist/spi/strategies/IAuthStrategy.d.ts.map +1 -0
- package/dist/spi/strategies/IAuthStrategy.js +16 -0
- package/dist/spi/strategies/IStrategyRegistry.d.ts +64 -0
- package/dist/spi/strategies/IStrategyRegistry.d.ts.map +1 -0
- package/dist/spi/strategies/IStrategyRegistry.js +5 -0
- package/dist/spi/strategies/index.d.ts +3 -0
- package/dist/spi/strategies/index.d.ts.map +1 -0
- package/dist/spi/strategies/index.js +2 -0
- package/package.json +78 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Storage Token Storage Implementation
|
|
3
|
+
* Persists tokens using browser sessionStorage (cleared when tab closes)
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Storage keys
|
|
7
|
+
*/
|
|
8
|
+
const STORAGE_KEYS = {
|
|
9
|
+
ACCESS_TOKEN: 'accessToken',
|
|
10
|
+
REFRESH_TOKEN: 'refreshToken',
|
|
11
|
+
EXPIRES_AT: 'expiresAt',
|
|
12
|
+
TOKEN_TYPE: 'tokenType',
|
|
13
|
+
SCOPE: 'scope',
|
|
14
|
+
USER: 'user'
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Token storage implementation using sessionStorage
|
|
18
|
+
* Tokens are cleared when the browser tab is closed
|
|
19
|
+
*/
|
|
20
|
+
export class SessionTokenStorage {
|
|
21
|
+
constructor(config = {}) {
|
|
22
|
+
this.keyPrefix = config.keyPrefix || '@hamak/auth';
|
|
23
|
+
}
|
|
24
|
+
getKey(key) {
|
|
25
|
+
return `${this.keyPrefix}:${key}`;
|
|
26
|
+
}
|
|
27
|
+
getItem(key) {
|
|
28
|
+
try {
|
|
29
|
+
return sessionStorage.getItem(this.getKey(key));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
setItem(key, value) {
|
|
36
|
+
try {
|
|
37
|
+
sessionStorage.setItem(this.getKey(key), value);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
console.warn('Failed to store item in sessionStorage:', key);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
removeItem(key) {
|
|
44
|
+
try {
|
|
45
|
+
sessionStorage.removeItem(this.getKey(key));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Ignore errors
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
getAccessToken() {
|
|
52
|
+
return this.getItem(STORAGE_KEYS.ACCESS_TOKEN);
|
|
53
|
+
}
|
|
54
|
+
setAccessToken(token, expiresAt) {
|
|
55
|
+
this.setItem(STORAGE_KEYS.ACCESS_TOKEN, token);
|
|
56
|
+
if (expiresAt !== undefined) {
|
|
57
|
+
this.setItem(STORAGE_KEYS.EXPIRES_AT, String(expiresAt));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
getRefreshToken() {
|
|
61
|
+
return this.getItem(STORAGE_KEYS.REFRESH_TOKEN);
|
|
62
|
+
}
|
|
63
|
+
setRefreshToken(token) {
|
|
64
|
+
this.setItem(STORAGE_KEYS.REFRESH_TOKEN, token);
|
|
65
|
+
}
|
|
66
|
+
getTokens() {
|
|
67
|
+
const accessToken = this.getAccessToken();
|
|
68
|
+
if (!accessToken) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const expiresAtStr = this.getItem(STORAGE_KEYS.EXPIRES_AT);
|
|
72
|
+
const scopeStr = this.getItem(STORAGE_KEYS.SCOPE);
|
|
73
|
+
return {
|
|
74
|
+
accessToken,
|
|
75
|
+
refreshToken: this.getRefreshToken() || undefined,
|
|
76
|
+
tokenType: this.getItem(STORAGE_KEYS.TOKEN_TYPE) || 'Bearer',
|
|
77
|
+
expiresAt: expiresAtStr ? parseInt(expiresAtStr, 10) : undefined,
|
|
78
|
+
scope: scopeStr ? JSON.parse(scopeStr) : undefined
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
setTokens(tokens) {
|
|
82
|
+
this.setAccessToken(tokens.accessToken, tokens.expiresAt);
|
|
83
|
+
if (tokens.refreshToken) {
|
|
84
|
+
this.setRefreshToken(tokens.refreshToken);
|
|
85
|
+
}
|
|
86
|
+
if (tokens.tokenType) {
|
|
87
|
+
this.setItem(STORAGE_KEYS.TOKEN_TYPE, tokens.tokenType);
|
|
88
|
+
}
|
|
89
|
+
if (tokens.scope) {
|
|
90
|
+
this.setItem(STORAGE_KEYS.SCOPE, JSON.stringify(tokens.scope));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
clearTokens() {
|
|
94
|
+
this.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
|
|
95
|
+
this.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
|
|
96
|
+
this.removeItem(STORAGE_KEYS.EXPIRES_AT);
|
|
97
|
+
this.removeItem(STORAGE_KEYS.TOKEN_TYPE);
|
|
98
|
+
this.removeItem(STORAGE_KEYS.SCOPE);
|
|
99
|
+
}
|
|
100
|
+
isTokenExpired() {
|
|
101
|
+
const accessToken = this.getAccessToken();
|
|
102
|
+
if (!accessToken) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
const expiresAt = this.getTokenExpiry();
|
|
106
|
+
if (!expiresAt) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
return Date.now() >= expiresAt;
|
|
110
|
+
}
|
|
111
|
+
isTokenExpiringSoon(thresholdMs) {
|
|
112
|
+
const expiresAt = this.getTokenExpiry();
|
|
113
|
+
if (!expiresAt) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
return Date.now() + thresholdMs >= expiresAt;
|
|
117
|
+
}
|
|
118
|
+
getTokenExpiry() {
|
|
119
|
+
const expiresAtStr = this.getItem(STORAGE_KEYS.EXPIRES_AT);
|
|
120
|
+
if (!expiresAtStr) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
return parseInt(expiresAtStr, 10);
|
|
124
|
+
}
|
|
125
|
+
getUser() {
|
|
126
|
+
const userStr = this.getItem(STORAGE_KEYS.USER);
|
|
127
|
+
if (!userStr) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
return JSON.parse(userStr);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
setUser(user) {
|
|
138
|
+
this.setItem(STORAGE_KEYS.USER, JSON.stringify(user));
|
|
139
|
+
}
|
|
140
|
+
clearUser() {
|
|
141
|
+
this.removeItem(STORAGE_KEYS.USER);
|
|
142
|
+
}
|
|
143
|
+
clearAll() {
|
|
144
|
+
this.clearTokens();
|
|
145
|
+
this.clearUser();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './LocalTokenStorage';
|
|
2
|
+
export * from './SessionTokenStorage';
|
|
3
|
+
export * from './MemoryTokenStorage';
|
|
4
|
+
import type { TokenStorageType } from '../../api';
|
|
5
|
+
import type { ITokenStorage, TokenStorageConfig } from '../../spi';
|
|
6
|
+
/**
|
|
7
|
+
* Factory function to create a token storage based on type
|
|
8
|
+
*/
|
|
9
|
+
export declare function createTokenStorage(type: TokenStorageType, config?: TokenStorageConfig): ITokenStorage;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/impl/storage/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AAErC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAKnE;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,gBAAgB,EACtB,MAAM,CAAC,EAAE,kBAAkB,GAC1B,aAAa,CAgBf"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export * from './LocalTokenStorage';
|
|
2
|
+
export * from './SessionTokenStorage';
|
|
3
|
+
export * from './MemoryTokenStorage';
|
|
4
|
+
import { LocalTokenStorage } from './LocalTokenStorage';
|
|
5
|
+
import { SessionTokenStorage } from './SessionTokenStorage';
|
|
6
|
+
import { MemoryTokenStorage } from './MemoryTokenStorage';
|
|
7
|
+
/**
|
|
8
|
+
* Factory function to create a token storage based on type
|
|
9
|
+
*/
|
|
10
|
+
export function createTokenStorage(type, config) {
|
|
11
|
+
switch (type) {
|
|
12
|
+
case 'localStorage':
|
|
13
|
+
return new LocalTokenStorage(config);
|
|
14
|
+
case 'sessionStorage':
|
|
15
|
+
return new SessionTokenStorage(config);
|
|
16
|
+
case 'memory':
|
|
17
|
+
return new MemoryTokenStorage();
|
|
18
|
+
case 'cookie':
|
|
19
|
+
// Cookie storage would require additional implementation
|
|
20
|
+
// Fall back to localStorage for now
|
|
21
|
+
console.warn('Cookie storage not implemented, falling back to localStorage');
|
|
22
|
+
return new LocalTokenStorage(config);
|
|
23
|
+
default:
|
|
24
|
+
return new LocalTokenStorage(config);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Redux Reducer
|
|
3
|
+
* State management for authentication
|
|
4
|
+
*/
|
|
5
|
+
import type { AuthError, User } from '../../api';
|
|
6
|
+
/**
|
|
7
|
+
* Auth state shape
|
|
8
|
+
*/
|
|
9
|
+
export interface AuthState {
|
|
10
|
+
/** Whether the user is authenticated */
|
|
11
|
+
isAuthenticated: boolean;
|
|
12
|
+
/** The current user */
|
|
13
|
+
user: User | null;
|
|
14
|
+
/** Whether an auth operation is in progress */
|
|
15
|
+
loading: boolean;
|
|
16
|
+
/** The last auth error */
|
|
17
|
+
error: AuthError | null;
|
|
18
|
+
/** Whether the auth service has been initialized */
|
|
19
|
+
initialized: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Auth action types
|
|
23
|
+
*/
|
|
24
|
+
export declare const AUTH_ACTION_TYPES: {
|
|
25
|
+
readonly INIT: "@hamak/auth/INIT";
|
|
26
|
+
readonly INIT_SUCCESS: "@hamak/auth/INIT_SUCCESS";
|
|
27
|
+
readonly INIT_FAILURE: "@hamak/auth/INIT_FAILURE";
|
|
28
|
+
readonly LOGIN_REQUEST: "@hamak/auth/LOGIN_REQUEST";
|
|
29
|
+
readonly LOGIN_SUCCESS: "@hamak/auth/LOGIN_SUCCESS";
|
|
30
|
+
readonly LOGIN_FAILURE: "@hamak/auth/LOGIN_FAILURE";
|
|
31
|
+
readonly LOGOUT: "@hamak/auth/LOGOUT";
|
|
32
|
+
readonly TOKEN_REFRESH: "@hamak/auth/TOKEN_REFRESH";
|
|
33
|
+
readonly TOKEN_REFRESH_SUCCESS: "@hamak/auth/TOKEN_REFRESH_SUCCESS";
|
|
34
|
+
readonly TOKEN_REFRESH_FAILURE: "@hamak/auth/TOKEN_REFRESH_FAILURE";
|
|
35
|
+
readonly SESSION_EXPIRED: "@hamak/auth/SESSION_EXPIRED";
|
|
36
|
+
readonly UPDATE_USER: "@hamak/auth/UPDATE_USER";
|
|
37
|
+
readonly CLEAR_ERROR: "@hamak/auth/CLEAR_ERROR";
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Auth action types
|
|
41
|
+
*/
|
|
42
|
+
export type AuthActionType = (typeof AUTH_ACTION_TYPES)[keyof typeof AUTH_ACTION_TYPES];
|
|
43
|
+
/**
|
|
44
|
+
* Auth actions
|
|
45
|
+
*/
|
|
46
|
+
export type AuthAction = {
|
|
47
|
+
type: typeof AUTH_ACTION_TYPES.INIT;
|
|
48
|
+
} | {
|
|
49
|
+
type: typeof AUTH_ACTION_TYPES.INIT_SUCCESS;
|
|
50
|
+
payload: {
|
|
51
|
+
user: User | null;
|
|
52
|
+
isAuthenticated: boolean;
|
|
53
|
+
};
|
|
54
|
+
} | {
|
|
55
|
+
type: typeof AUTH_ACTION_TYPES.INIT_FAILURE;
|
|
56
|
+
payload: AuthError;
|
|
57
|
+
} | {
|
|
58
|
+
type: typeof AUTH_ACTION_TYPES.LOGIN_REQUEST;
|
|
59
|
+
} | {
|
|
60
|
+
type: typeof AUTH_ACTION_TYPES.LOGIN_SUCCESS;
|
|
61
|
+
payload: {
|
|
62
|
+
user: User;
|
|
63
|
+
};
|
|
64
|
+
} | {
|
|
65
|
+
type: typeof AUTH_ACTION_TYPES.LOGIN_FAILURE;
|
|
66
|
+
payload: AuthError;
|
|
67
|
+
} | {
|
|
68
|
+
type: typeof AUTH_ACTION_TYPES.LOGOUT;
|
|
69
|
+
} | {
|
|
70
|
+
type: typeof AUTH_ACTION_TYPES.TOKEN_REFRESH;
|
|
71
|
+
} | {
|
|
72
|
+
type: typeof AUTH_ACTION_TYPES.TOKEN_REFRESH_SUCCESS;
|
|
73
|
+
payload: {
|
|
74
|
+
user?: User;
|
|
75
|
+
};
|
|
76
|
+
} | {
|
|
77
|
+
type: typeof AUTH_ACTION_TYPES.TOKEN_REFRESH_FAILURE;
|
|
78
|
+
payload: AuthError;
|
|
79
|
+
} | {
|
|
80
|
+
type: typeof AUTH_ACTION_TYPES.SESSION_EXPIRED;
|
|
81
|
+
} | {
|
|
82
|
+
type: typeof AUTH_ACTION_TYPES.UPDATE_USER;
|
|
83
|
+
payload: User;
|
|
84
|
+
} | {
|
|
85
|
+
type: typeof AUTH_ACTION_TYPES.CLEAR_ERROR;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Auth reducer
|
|
89
|
+
*/
|
|
90
|
+
export declare function authReducer(state: AuthState | undefined, action: AuthAction): AuthState;
|
|
91
|
+
/**
|
|
92
|
+
* Action creators
|
|
93
|
+
*/
|
|
94
|
+
export declare const authActions: {
|
|
95
|
+
init: () => AuthAction;
|
|
96
|
+
initSuccess: (user: User | null, isAuthenticated: boolean) => AuthAction;
|
|
97
|
+
initFailure: (error: AuthError) => AuthAction;
|
|
98
|
+
loginRequest: () => AuthAction;
|
|
99
|
+
loginSuccess: (user: User) => AuthAction;
|
|
100
|
+
loginFailure: (error: AuthError) => AuthAction;
|
|
101
|
+
logout: () => AuthAction;
|
|
102
|
+
tokenRefresh: () => AuthAction;
|
|
103
|
+
tokenRefreshSuccess: (user?: User) => AuthAction;
|
|
104
|
+
tokenRefreshFailure: (error: AuthError) => AuthAction;
|
|
105
|
+
sessionExpired: () => AuthAction;
|
|
106
|
+
updateUser: (user: User) => AuthAction;
|
|
107
|
+
clearError: () => AuthAction;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Selectors
|
|
111
|
+
*/
|
|
112
|
+
export declare const authSelectors: {
|
|
113
|
+
selectIsAuthenticated: (state: {
|
|
114
|
+
auth: AuthState;
|
|
115
|
+
}) => boolean;
|
|
116
|
+
selectUser: (state: {
|
|
117
|
+
auth: AuthState;
|
|
118
|
+
}) => User | null;
|
|
119
|
+
selectIsLoading: (state: {
|
|
120
|
+
auth: AuthState;
|
|
121
|
+
}) => boolean;
|
|
122
|
+
selectError: (state: {
|
|
123
|
+
auth: AuthState;
|
|
124
|
+
}) => AuthError | null;
|
|
125
|
+
selectIsInitialized: (state: {
|
|
126
|
+
auth: AuthState;
|
|
127
|
+
}) => boolean;
|
|
128
|
+
selectRoles: (state: {
|
|
129
|
+
auth: AuthState;
|
|
130
|
+
}) => string[];
|
|
131
|
+
selectPermissions: (state: {
|
|
132
|
+
auth: AuthState;
|
|
133
|
+
}) => string[];
|
|
134
|
+
};
|
|
135
|
+
//# sourceMappingURL=auth-reducer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-reducer.d.ts","sourceRoot":"","sources":["../../../src/impl/store/auth-reducer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,wCAAwC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,uBAAuB;IACvB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,+CAA+C;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,0BAA0B;IAC1B,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,oDAAoD;IACpD,WAAW,EAAE,OAAO,CAAC;CACtB;AAaD;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;CAcpB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;AAExF;;GAEG;AACH,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,IAAI,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,YAAY,CAAC;IAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;QAAC,eAAe,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACzG;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,YAAY,CAAC;IAAC,OAAO,EAAE,SAAS,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,aAAa,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,aAAa,CAAC;IAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,aAAa,CAAC;IAAC,OAAO,EAAE,SAAS,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,aAAa,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,qBAAqB,CAAC;IAAC,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,IAAI,CAAA;KAAE,CAAA;CAAE,GAClF;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,qBAAqB,CAAC;IAAC,OAAO,EAAE,SAAS,CAAA;CAAE,GAC5E;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,eAAe,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,WAAW,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,OAAO,iBAAiB,CAAC,WAAW,CAAA;CAAE,CAAC;AAEnD;;GAEG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,YAAe,EAC/B,MAAM,EAAE,UAAU,GACjB,SAAS,CAyGX;AAED;;GAEG;AACH,eAAO,MAAM,WAAW;gBACZ,UAAU;wBAEA,IAAI,GAAG,IAAI,mBAAmB,OAAO,KAAG,UAAU;yBAKjD,SAAS,KAAG,UAAU;wBAKzB,UAAU;yBAEP,IAAI,KAAG,UAAU;0BAKhB,SAAS,KAAG,UAAU;kBAKhC,UAAU;wBAEJ,UAAU;iCAEC,IAAI,KAAG,UAAU;iCAKjB,SAAS,KAAG,UAAU;0BAK/B,UAAU;uBAEX,IAAI,KAAG,UAAU;sBAKpB,UAAU;CAC3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa;mCACO;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,KAAG,OAAO;wBAGxC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,KAAG,IAAI,GAAG,IAAI;6BAG5B;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,KAAG,OAAO;yBAGjC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,KAAG,SAAS,GAAG,IAAI;iCAG9B;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,KAAG,OAAO;yBAGrC;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,KAAG,MAAM,EAAE;+BAGxB;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,KAAG,MAAM,EAAE;CAE1D,CAAC"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Redux Reducer
|
|
3
|
+
* State management for authentication
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Initial auth state
|
|
7
|
+
*/
|
|
8
|
+
const initialState = {
|
|
9
|
+
isAuthenticated: false,
|
|
10
|
+
user: null,
|
|
11
|
+
loading: false,
|
|
12
|
+
error: null,
|
|
13
|
+
initialized: false
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Auth action types
|
|
17
|
+
*/
|
|
18
|
+
export const AUTH_ACTION_TYPES = {
|
|
19
|
+
INIT: '@hamak/auth/INIT',
|
|
20
|
+
INIT_SUCCESS: '@hamak/auth/INIT_SUCCESS',
|
|
21
|
+
INIT_FAILURE: '@hamak/auth/INIT_FAILURE',
|
|
22
|
+
LOGIN_REQUEST: '@hamak/auth/LOGIN_REQUEST',
|
|
23
|
+
LOGIN_SUCCESS: '@hamak/auth/LOGIN_SUCCESS',
|
|
24
|
+
LOGIN_FAILURE: '@hamak/auth/LOGIN_FAILURE',
|
|
25
|
+
LOGOUT: '@hamak/auth/LOGOUT',
|
|
26
|
+
TOKEN_REFRESH: '@hamak/auth/TOKEN_REFRESH',
|
|
27
|
+
TOKEN_REFRESH_SUCCESS: '@hamak/auth/TOKEN_REFRESH_SUCCESS',
|
|
28
|
+
TOKEN_REFRESH_FAILURE: '@hamak/auth/TOKEN_REFRESH_FAILURE',
|
|
29
|
+
SESSION_EXPIRED: '@hamak/auth/SESSION_EXPIRED',
|
|
30
|
+
UPDATE_USER: '@hamak/auth/UPDATE_USER',
|
|
31
|
+
CLEAR_ERROR: '@hamak/auth/CLEAR_ERROR'
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Auth reducer
|
|
35
|
+
*/
|
|
36
|
+
export function authReducer(state = initialState, action) {
|
|
37
|
+
switch (action.type) {
|
|
38
|
+
case AUTH_ACTION_TYPES.INIT:
|
|
39
|
+
return {
|
|
40
|
+
...state,
|
|
41
|
+
loading: true,
|
|
42
|
+
error: null
|
|
43
|
+
};
|
|
44
|
+
case AUTH_ACTION_TYPES.INIT_SUCCESS:
|
|
45
|
+
return {
|
|
46
|
+
...state,
|
|
47
|
+
loading: false,
|
|
48
|
+
initialized: true,
|
|
49
|
+
isAuthenticated: action.payload.isAuthenticated,
|
|
50
|
+
user: action.payload.user,
|
|
51
|
+
error: null
|
|
52
|
+
};
|
|
53
|
+
case AUTH_ACTION_TYPES.INIT_FAILURE:
|
|
54
|
+
return {
|
|
55
|
+
...state,
|
|
56
|
+
loading: false,
|
|
57
|
+
initialized: true,
|
|
58
|
+
isAuthenticated: false,
|
|
59
|
+
user: null,
|
|
60
|
+
error: action.payload
|
|
61
|
+
};
|
|
62
|
+
case AUTH_ACTION_TYPES.LOGIN_REQUEST:
|
|
63
|
+
return {
|
|
64
|
+
...state,
|
|
65
|
+
loading: true,
|
|
66
|
+
error: null
|
|
67
|
+
};
|
|
68
|
+
case AUTH_ACTION_TYPES.LOGIN_SUCCESS:
|
|
69
|
+
return {
|
|
70
|
+
...state,
|
|
71
|
+
loading: false,
|
|
72
|
+
isAuthenticated: true,
|
|
73
|
+
user: action.payload.user,
|
|
74
|
+
error: null
|
|
75
|
+
};
|
|
76
|
+
case AUTH_ACTION_TYPES.LOGIN_FAILURE:
|
|
77
|
+
return {
|
|
78
|
+
...state,
|
|
79
|
+
loading: false,
|
|
80
|
+
isAuthenticated: false,
|
|
81
|
+
user: null,
|
|
82
|
+
error: action.payload
|
|
83
|
+
};
|
|
84
|
+
case AUTH_ACTION_TYPES.LOGOUT:
|
|
85
|
+
return {
|
|
86
|
+
...initialState,
|
|
87
|
+
initialized: true
|
|
88
|
+
};
|
|
89
|
+
case AUTH_ACTION_TYPES.TOKEN_REFRESH:
|
|
90
|
+
return {
|
|
91
|
+
...state,
|
|
92
|
+
// Don't set loading for background refresh
|
|
93
|
+
error: null
|
|
94
|
+
};
|
|
95
|
+
case AUTH_ACTION_TYPES.TOKEN_REFRESH_SUCCESS:
|
|
96
|
+
return {
|
|
97
|
+
...state,
|
|
98
|
+
user: action.payload.user || state.user,
|
|
99
|
+
error: null
|
|
100
|
+
};
|
|
101
|
+
case AUTH_ACTION_TYPES.TOKEN_REFRESH_FAILURE:
|
|
102
|
+
return {
|
|
103
|
+
...state,
|
|
104
|
+
error: action.payload
|
|
105
|
+
};
|
|
106
|
+
case AUTH_ACTION_TYPES.SESSION_EXPIRED:
|
|
107
|
+
return {
|
|
108
|
+
...initialState,
|
|
109
|
+
initialized: true,
|
|
110
|
+
error: {
|
|
111
|
+
code: 'token_expired',
|
|
112
|
+
message: 'Your session has expired. Please login again.'
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
case AUTH_ACTION_TYPES.UPDATE_USER:
|
|
116
|
+
return {
|
|
117
|
+
...state,
|
|
118
|
+
user: action.payload
|
|
119
|
+
};
|
|
120
|
+
case AUTH_ACTION_TYPES.CLEAR_ERROR:
|
|
121
|
+
return {
|
|
122
|
+
...state,
|
|
123
|
+
error: null
|
|
124
|
+
};
|
|
125
|
+
default:
|
|
126
|
+
return state;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Action creators
|
|
131
|
+
*/
|
|
132
|
+
export const authActions = {
|
|
133
|
+
init: () => ({ type: AUTH_ACTION_TYPES.INIT }),
|
|
134
|
+
initSuccess: (user, isAuthenticated) => ({
|
|
135
|
+
type: AUTH_ACTION_TYPES.INIT_SUCCESS,
|
|
136
|
+
payload: { user, isAuthenticated }
|
|
137
|
+
}),
|
|
138
|
+
initFailure: (error) => ({
|
|
139
|
+
type: AUTH_ACTION_TYPES.INIT_FAILURE,
|
|
140
|
+
payload: error
|
|
141
|
+
}),
|
|
142
|
+
loginRequest: () => ({ type: AUTH_ACTION_TYPES.LOGIN_REQUEST }),
|
|
143
|
+
loginSuccess: (user) => ({
|
|
144
|
+
type: AUTH_ACTION_TYPES.LOGIN_SUCCESS,
|
|
145
|
+
payload: { user }
|
|
146
|
+
}),
|
|
147
|
+
loginFailure: (error) => ({
|
|
148
|
+
type: AUTH_ACTION_TYPES.LOGIN_FAILURE,
|
|
149
|
+
payload: error
|
|
150
|
+
}),
|
|
151
|
+
logout: () => ({ type: AUTH_ACTION_TYPES.LOGOUT }),
|
|
152
|
+
tokenRefresh: () => ({ type: AUTH_ACTION_TYPES.TOKEN_REFRESH }),
|
|
153
|
+
tokenRefreshSuccess: (user) => ({
|
|
154
|
+
type: AUTH_ACTION_TYPES.TOKEN_REFRESH_SUCCESS,
|
|
155
|
+
payload: { user }
|
|
156
|
+
}),
|
|
157
|
+
tokenRefreshFailure: (error) => ({
|
|
158
|
+
type: AUTH_ACTION_TYPES.TOKEN_REFRESH_FAILURE,
|
|
159
|
+
payload: error
|
|
160
|
+
}),
|
|
161
|
+
sessionExpired: () => ({ type: AUTH_ACTION_TYPES.SESSION_EXPIRED }),
|
|
162
|
+
updateUser: (user) => ({
|
|
163
|
+
type: AUTH_ACTION_TYPES.UPDATE_USER,
|
|
164
|
+
payload: user
|
|
165
|
+
}),
|
|
166
|
+
clearError: () => ({ type: AUTH_ACTION_TYPES.CLEAR_ERROR })
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Selectors
|
|
170
|
+
*/
|
|
171
|
+
export const authSelectors = {
|
|
172
|
+
selectIsAuthenticated: (state) => state.auth.isAuthenticated,
|
|
173
|
+
selectUser: (state) => state.auth.user,
|
|
174
|
+
selectIsLoading: (state) => state.auth.loading,
|
|
175
|
+
selectError: (state) => state.auth.error,
|
|
176
|
+
selectIsInitialized: (state) => state.auth.initialized,
|
|
177
|
+
selectRoles: (state) => state.auth.user?.roles || [],
|
|
178
|
+
selectPermissions: (state) => state.auth.user?.permissions || []
|
|
179
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/impl/store/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './auth-reducer';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keycloak Authentication Strategy
|
|
3
|
+
* Implements authentication with Keycloak identity provider
|
|
4
|
+
*/
|
|
5
|
+
import type { AuthResult, KeycloakStrategyConfig, LoginCredentials, OAuthCallbackParams, User } from '../../api';
|
|
6
|
+
import type { IDirectAuthStrategy, IOAuthStrategy, IHttpClient } from '../../spi';
|
|
7
|
+
/**
|
|
8
|
+
* Keycloak authentication strategy
|
|
9
|
+
*
|
|
10
|
+
* Extends OAuth2 strategy with Keycloak-specific features:
|
|
11
|
+
* - Direct grant (password) authentication
|
|
12
|
+
* - Role extraction from JWT tokens
|
|
13
|
+
* - Keycloak realm and resource roles
|
|
14
|
+
* - Proper logout with session invalidation
|
|
15
|
+
*/
|
|
16
|
+
export declare class KeycloakStrategy implements IOAuthStrategy, IDirectAuthStrategy {
|
|
17
|
+
private readonly config;
|
|
18
|
+
private readonly httpClient;
|
|
19
|
+
readonly type: "keycloak";
|
|
20
|
+
readonly name: string;
|
|
21
|
+
private readonly oauth2;
|
|
22
|
+
private readonly baseUrl;
|
|
23
|
+
private readonly tokenUrl;
|
|
24
|
+
private readonly logoutUrl;
|
|
25
|
+
constructor(config: KeycloakStrategyConfig, httpClient: IHttpClient, name?: string);
|
|
26
|
+
getAuthorizationUrl(): Promise<string>;
|
|
27
|
+
handleCallback(params: OAuthCallbackParams): Promise<AuthResult>;
|
|
28
|
+
authenticate(credentials: LoginCredentials): Promise<AuthResult>;
|
|
29
|
+
authenticateDirect(username: string, password: string): Promise<AuthResult>;
|
|
30
|
+
refreshToken(refreshToken: string): Promise<AuthResult>;
|
|
31
|
+
logout(accessToken: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Logout with refresh token for complete session invalidation
|
|
34
|
+
*/
|
|
35
|
+
logoutWithRefreshToken(refreshToken: string): Promise<void>;
|
|
36
|
+
getStoredState(): string | null;
|
|
37
|
+
clearOAuthState(): void;
|
|
38
|
+
extractUserFromToken(token: string): User | null;
|
|
39
|
+
private extractUserWithRoles;
|
|
40
|
+
private handleKeycloakError;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=KeycloakStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeycloakStrategy.d.ts","sourceRoot":"","sources":["../../../src/impl/strategies/KeycloakStrategy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,EACnB,IAAI,EACL,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAkBlF;;;;;;;;GAQG;AACH,qBAAa,gBAAiB,YAAW,cAAc,EAAE,mBAAmB;IAUxE,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAV7B,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAU;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAGhB,MAAM,EAAE,sBAAsB,EAC9B,UAAU,EAAE,WAAW,EACxC,IAAI,SAAa;IAyBb,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAItC,cAAc,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;IAWhE,YAAY,CAAC,WAAW,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAuBhE,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IA+C3E,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAmCvD,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBhD;;OAEG;IACG,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBjE,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B,eAAe,IAAI,IAAI;IAIvB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIhD,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,mBAAmB;CA8D5B"}
|