feat: switch to oidc-client-rx
This commit is contained in:
@@ -1,31 +1,42 @@
|
||||
import { type OidcClientSettings, UserManager } from 'oidc-client-ts';
|
||||
import { InjectionToken } from '@outposts/injection-js';
|
||||
import {
|
||||
type EventTypes,
|
||||
LogLevel,
|
||||
type OpenIdConfiguration,
|
||||
} from 'oidc-client-rx';
|
||||
|
||||
export const PostLoginRedirectUriKey = 'post_login_redirect_uri';
|
||||
export const isBasicAuth = process.env.AUTH_TYPE === 'basic';
|
||||
|
||||
export function buildOidcConfig(): OidcClientSettings {
|
||||
export function buildOidcConfig(): OpenIdConfiguration {
|
||||
const origin = window.location.origin;
|
||||
|
||||
const resource = process.env.OIDC_AUDIENCE!;
|
||||
|
||||
return {
|
||||
authority: process.env.OIDC_ISSUER!,
|
||||
client_id: process.env.OIDC_CLIENT_ID!,
|
||||
client_secret: process.env.OIDC_CLIENT_SECRET!,
|
||||
redirect_uri: `${origin}/api/playground/oidc/callback`,
|
||||
disablePKCE: false,
|
||||
scope: `openid profile email ${process.env.OIDC_EXTRA_SCOPES}`,
|
||||
response_type: 'code',
|
||||
resource,
|
||||
post_logout_redirect_uri: `${origin}/api/playground`,
|
||||
extraQueryParams: {
|
||||
redirectUrl: `${origin}/api/playground/oidc/callback`,
|
||||
postLogoutRedirectUri: `${origin}/api/playground`,
|
||||
clientId: process.env.OIDC_CLIENT_ID!,
|
||||
clientSecret: process.env.OIDC_CLIENT_SECRET,
|
||||
scope: process.env.OIDC_EXTRA_SCOPES
|
||||
? `openid profile email offline_access ${process.env.OIDC_EXTRA_SCOPES}`
|
||||
: 'openid profile email offline_access',
|
||||
triggerAuthorizationResultEvent: true,
|
||||
responseType: 'code',
|
||||
silentRenew: true,
|
||||
useRefreshToken: true,
|
||||
logLevel: LogLevel.Debug,
|
||||
autoUserInfo: !resource,
|
||||
renewUserInfoAfterTokenRenew: !resource,
|
||||
customParamsAuthRequest: {
|
||||
prompt: 'consent',
|
||||
resource,
|
||||
},
|
||||
extraTokenParams: {
|
||||
customParamsRefreshTokenRequest: {
|
||||
resource,
|
||||
},
|
||||
customParamsCodeRequest: {
|
||||
resource,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function buildUserManager(): UserManager {
|
||||
return new UserManager(buildOidcConfig());
|
||||
}
|
||||
|
||||
41
apps/recorder/src/auth/event.ts
Normal file
41
apps/recorder/src/auth/event.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import type { Observable } from '@graphiql/toolkit';
|
||||
import { InjectionToken, inject } from '@outposts/injection-js';
|
||||
import {
|
||||
type AuthFeature,
|
||||
EventTypes,
|
||||
PublicEventsService,
|
||||
} from 'oidc-client-rx';
|
||||
import { filter, shareReplay } from 'rxjs';
|
||||
|
||||
export type CheckAuthResultEventType =
|
||||
| { type: EventTypes.CheckingAuthFinished }
|
||||
| {
|
||||
type: EventTypes.CheckingAuthFinishedWithError;
|
||||
value: string;
|
||||
};
|
||||
export const CHECK_AUTH_RESULT_EVENT = new InjectionToken<
|
||||
Observable<CheckAuthResultEventType>
|
||||
>('CHECK_AUTH_RESULT_EVENT');
|
||||
|
||||
export function withCheckAuthResultEvent(): AuthFeature {
|
||||
return {
|
||||
ɵproviders: [
|
||||
{
|
||||
provide: CHECK_AUTH_RESULT_EVENT,
|
||||
useFactory: () => {
|
||||
const publishEventService = inject(PublicEventsService);
|
||||
|
||||
return publishEventService.registerForEvents().pipe(
|
||||
filter(
|
||||
(e) =>
|
||||
e.type === EventTypes.CheckingAuthFinishedWithError ||
|
||||
e.type === EventTypes.CheckingAuthFinished
|
||||
),
|
||||
shareReplay(1)
|
||||
);
|
||||
},
|
||||
deps: [PublicEventsService],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -1,21 +1,19 @@
|
||||
import type { ParsedLocation } from '@tanstack/react-router';
|
||||
import { runInInjectionContext } from '@outposts/injection-js';
|
||||
import { autoLoginPartialRoutesGuard } from 'oidc-client-rx';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import type { RouterContext } from '../controllers/__root';
|
||||
import { PostLoginRedirectUriKey } from './config';
|
||||
|
||||
export const beforeLoadGuard = async ({
|
||||
context,
|
||||
location,
|
||||
// biome-ignore lint/complexity/noBannedTypes: <explanation>
|
||||
}: { context: RouterContext; location: ParsedLocation<{}> }) => {
|
||||
}: { context: RouterContext }) => {
|
||||
if (!context.isAuthenticated) {
|
||||
// TODO: FIXME
|
||||
const user = await context.userManager.getUser();
|
||||
if (!user) {
|
||||
try {
|
||||
sessionStorage.setItem(PostLoginRedirectUriKey, location.href);
|
||||
// biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>
|
||||
} catch {}
|
||||
throw await context.auth.signinRedirect();
|
||||
const guard$ = runInInjectionContext(context.injector, () =>
|
||||
autoLoginPartialRoutesGuard()
|
||||
);
|
||||
|
||||
const isAuthenticated = await firstValueFrom(guard$);
|
||||
if (!isAuthenticated) {
|
||||
throw !isAuthenticated;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
52
apps/recorder/src/auth/hooks.ts
Normal file
52
apps/recorder/src/auth/hooks.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { useObservableEagerState, useObservableState } from 'observable-hooks';
|
||||
import {
|
||||
InjectorContextVoidInjector,
|
||||
useOidcClient,
|
||||
} from 'oidc-client-rx/adapters/react';
|
||||
import { useMemo } from 'react';
|
||||
import { NEVER, type Observable, of } from 'rxjs';
|
||||
import { isBasicAuth } from './config';
|
||||
import {
|
||||
CHECK_AUTH_RESULT_EVENT,
|
||||
type CheckAuthResultEventType,
|
||||
} from './event';
|
||||
|
||||
const BASIC_AUTH_IS_AUTHENTICATED$ = of({
|
||||
isAuthenticated: true,
|
||||
allConfigsAuthenticated: [],
|
||||
});
|
||||
|
||||
const BASIC_AUTH_USER_DATA$ = of({
|
||||
userData: {},
|
||||
allUserData: [],
|
||||
});
|
||||
|
||||
export function useAuth() {
|
||||
const { oidcSecurityService, injector } = isBasicAuth
|
||||
? { oidcSecurityService: undefined, injector: InjectorContextVoidInjector }
|
||||
: // biome-ignore lint/correctness/useHookAtTopLevel: <explanation>
|
||||
useOidcClient();
|
||||
|
||||
const { isAuthenticated } = useObservableEagerState(
|
||||
oidcSecurityService?.isAuthenticated$ ?? BASIC_AUTH_IS_AUTHENTICATED$
|
||||
);
|
||||
|
||||
const { userData } = useObservableEagerState(
|
||||
oidcSecurityService?.userData$ ?? BASIC_AUTH_USER_DATA$
|
||||
);
|
||||
|
||||
const checkAuthResultEvent = useObservableState(
|
||||
useMemo(
|
||||
() => (isBasicAuth ? NEVER : injector.get(CHECK_AUTH_RESULT_EVENT)),
|
||||
[injector]
|
||||
) as Observable<CheckAuthResultEventType>
|
||||
);
|
||||
|
||||
return {
|
||||
oidcSecurityService,
|
||||
isAuthenticated,
|
||||
userData,
|
||||
injector,
|
||||
checkAuthResultEvent,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user