User session
This lightweight package provides helpers to manage user session.
Getting started
Session API example
export type SessionCredentials = {
userName: string,
password: string,
};
export default class SessionApi implements SessionRefresher {
constructor(private readonly httpClient: ApiHttpClient) {
}
authenticate(credentials: SessionCredentials) {
return this
.httpClient
.restRequest<RefreshableJwtToken>(HttpMethod.POST, '/admin/session')
.jsonBody(credentials)
.execute();
}
refresh(webSessionToken: string) {
return this
.httpClient
.restRequest<RefreshableJwtToken>(HttpMethod.PUT, '/admin/session')
.body(webSessionToken)
.execute();
}
}
User type example
export type User = {
idUser: string,
userName: string,
fullName: string,
permissions: string[],
};
User type with expiration example
export type UserWithExpiration = User & {
exp: number;
}
Session service example
const THRESHOLD_IN_MILLIS_TO_DETECT_EXPIRED_SESSION = 60 * 1000;
const LOCAL_STORAGE_CURRENT_SESSION = 'user-session';
const HTTP_ERROR_ALREADY_EXPIRED_SESSION_TOKEN = 'ALREADY_EXPIRED_SESSION_TOKEN';
export default class SessionService {
private jwtSessionManager: JwtSessionManager<UserWithExpiration>;
constructor(
private readonly sessionApi: SessionApi,
private readonly scheduler: Scheduler,
private readonly pageActivityManager: PageActivityManager,
private readonly idlenessDetector: IdlenessDetector
) {
this.jwtSessionManager = new JwtSessionManager<UserWithExpiration>(
sessionApi,
scheduler,
pageActivityManager,
idlenessDetector,
{
localStorageCurrentSession: LOCAL_STORAGE_CURRENT_SESSION,
thresholdInMillisToDetectExpiredSession: THRESHOLD_IN_MILLIS_TO_DETECT_EXPIRED_SESSION,
httpErrorAlreadyExpiredSessionToken: HTTP_ERROR_ALREADY_EXPIRED_SESSION_TOKEN,
},
);
}
getSessionToken() {
return this.jwtSessionManager.getSessionToken();
}
getCurrentUser() {
return this.jwtSessionManager.getCurrentUser();
}
isAuthenticated() {
return this.jwtSessionManager.isAuthenticated();
}
hasPermission(permission: Permission) {
return this.jwtSessionManager.getCurrentUser().select((user) => user?.permissions.includes(permission) ?? false);
}
authenticate(credentials: SessionCredentials) {
return this
.sessionApi
.authenticate(credentials)
.then((sessionToken) => this.jwtSessionManager.registerNewSession(sessionToken));
}
disconnect() {
this.jwtSessionManager.disconnect();
}
tryInitializingSessionFromStorage() {
this.jwtSessionManager.tryInitializingSessionFromStorage();
}
synchronizeSessionFromOtherBrowserTags() {
this.jwtSessionManager.synchronizeSessionFromOtherBrowserTags();
}
}
Services binding example
injector.registerSingleton(BrowserUserActivityListener, UserActivityListener);
injector.registerSingleton(IdlenessDetector);
injector.registerSingleton(SessionService);
Project startup configuration example
In index.ts
file:
const sessionService = injector.getInstance(SessionService);
sessionService.tryInitializingSessionFromStorage();
sessionService.synchronizeSessionFromOtherBrowserTags();
Protected routes example
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/*"
element={(
<ConditionalRoute shouldDisplayRoute={sessionService.isAuthenticated()} defaultRoute="/login">
<div id="main-layout">
<Navigation />
<div id="content-layout">
<Header />
<Router />
</div>
</div>
</ConditionalRoute>
)}
/>
</Routes>
Login page example
const tryAuthenticate = (credentials: SessionCredentials) => {
loader.monitor(sessionService.authenticate(credentials));
};
const isAuthenticated = useObservable(sessionService.isAuthenticated());
useOnDependenciesChange(() => {
if (isAuthenticated) {
navigate({ pathname: HOME });
}
}, [isAuthenticated]);