From cc67dd3aab3b212cdc14c082715c7a12f1e659f3 Mon Sep 17 00:00:00 2001 From: Alex Billingsley Date: Thu, 30 Oct 2025 10:29:41 -0400 Subject: [PATCH] expose logging options --- .../example/src/authentication-provider.tsx | 3 + .../src/__tests__/auth0-provider.test.tsx | 57 +++++- .../src/__tests__/azure-provider.test.tsx | 57 ++++++ .../src/__tests__/cognito-provider.test.tsx | 55 ++++++ .../src/__tests__/oidc-provider.test.tsx | 181 ++++++++++++++++++ packages/oidc-provider/src/auth-provider.ts | 4 + packages/oidc-provider/src/index.ts | 3 +- packages/oidc-provider/src/oidc-provider.tsx | 19 +- 8 files changed, 376 insertions(+), 3 deletions(-) diff --git a/packages/example/src/authentication-provider.tsx b/packages/example/src/authentication-provider.tsx index 1ed2af8..9af4164 100644 --- a/packages/example/src/authentication-provider.tsx +++ b/packages/example/src/authentication-provider.tsx @@ -1,4 +1,5 @@ import { + Log, // CognitoProvider as OpenIDAuthenticationProvider, // useCongito as useAuth, Auth0Provider as OpenIDAuthenticationProvider, @@ -59,6 +60,8 @@ export const AuthenticationProvider: React.FC = ({ return ( diff --git a/packages/oidc-provider/src/__tests__/auth0-provider.test.tsx b/packages/oidc-provider/src/__tests__/auth0-provider.test.tsx index 89f9141..e1d3645 100644 --- a/packages/oidc-provider/src/__tests__/auth0-provider.test.tsx +++ b/packages/oidc-provider/src/__tests__/auth0-provider.test.tsx @@ -9,8 +9,17 @@ import * as utils from "../utils"; vi.mock("oidc-client-ts", () => ({ UserManager: vi.fn(), WebStorageStateStore: vi.fn(), + Log: { + setLogger: vi.fn(), + setLevel: vi.fn(), + NONE: 0, + ERROR: 1, + WARN: 2, + INFO: 3, + DEBUG: 4, + }, InMemoryWebStorage: class InMemoryWebStorage { - private storage: Map = new Map(); + private readonly storage: Map = new Map(); get length() { return this.storage.size; } @@ -643,6 +652,52 @@ describe("Auth0Provider", () => { }); }); + describe("Logger Configuration", () => { + it("should pass logger prop to OIDCProvider", async () => { + const { Log } = await import("oidc-client-ts"); + const mockLogger = { + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + }; + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLogger).toHaveBeenCalledWith(mockLogger); + }); + }); + + it("should pass logLevel prop to OIDCProvider", async () => { + const { Log } = await import("oidc-client-ts"); + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLevel).toHaveBeenCalledWith(Log.DEBUG); + }); + }); + }); + describe("Integration with OIDCProvider", () => { it("should pass through additional OIDC provider props", async () => { render( diff --git a/packages/oidc-provider/src/__tests__/azure-provider.test.tsx b/packages/oidc-provider/src/__tests__/azure-provider.test.tsx index e46a1eb..ea22215 100644 --- a/packages/oidc-provider/src/__tests__/azure-provider.test.tsx +++ b/packages/oidc-provider/src/__tests__/azure-provider.test.tsx @@ -9,6 +9,15 @@ import * as utils from "../utils"; vi.mock("oidc-client-ts", () => ({ UserManager: vi.fn(), WebStorageStateStore: vi.fn(), + Log: { + setLogger: vi.fn(), + setLevel: vi.fn(), + NONE: 0, + ERROR: 1, + WARN: 2, + INFO: 3, + DEBUG: 4, + }, InMemoryWebStorage: class InMemoryWebStorage { private readonly storage: Map = new Map(); get length() { @@ -618,6 +627,54 @@ describe("AzureProvider", () => { }); }); + describe("Logger Configuration", () => { + it("should pass logger prop to OIDCProvider", async () => { + const { Log } = await import("oidc-client-ts"); + const mockLogger = { + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + }; + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLogger).toHaveBeenCalledWith(mockLogger); + }); + }); + + it("should pass logLevel prop to OIDCProvider", async () => { + const { Log } = await import("oidc-client-ts"); + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLevel).toHaveBeenCalledWith(Log.WARN); + }); + }); + }); + describe("Integration with OIDCProvider", () => { it("should pass through additional OIDC provider props", async () => { render( diff --git a/packages/oidc-provider/src/__tests__/cognito-provider.test.tsx b/packages/oidc-provider/src/__tests__/cognito-provider.test.tsx index 3d44690..d605488 100644 --- a/packages/oidc-provider/src/__tests__/cognito-provider.test.tsx +++ b/packages/oidc-provider/src/__tests__/cognito-provider.test.tsx @@ -9,6 +9,15 @@ import * as utils from "../utils"; vi.mock("oidc-client-ts", () => ({ UserManager: vi.fn(), WebStorageStateStore: vi.fn(), + Log: { + setLogger: vi.fn(), + setLevel: vi.fn(), + NONE: 0, + ERROR: 1, + WARN: 2, + INFO: 3, + DEBUG: 4, + }, InMemoryWebStorage: class InMemoryWebStorage { private readonly storage: Map = new Map(); get length() { @@ -594,6 +603,52 @@ describe("CognitoProvider", () => { }); }); + describe("Logger Configuration", () => { + it("should pass logger prop to OIDCProvider", async () => { + const { Log } = await import("oidc-client-ts"); + const mockLogger = { + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + }; + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLogger).toHaveBeenCalledWith(mockLogger); + }); + }); + + it("should pass logLevel prop to OIDCProvider", async () => { + const { Log } = await import("oidc-client-ts"); + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLevel).toHaveBeenCalledWith(Log.INFO); + }); + }); + }); + describe("Integration with OIDCProvider", () => { it("should pass through additional OIDC provider props", async () => { render( diff --git a/packages/oidc-provider/src/__tests__/oidc-provider.test.tsx b/packages/oidc-provider/src/__tests__/oidc-provider.test.tsx index 820887b..317da95 100644 --- a/packages/oidc-provider/src/__tests__/oidc-provider.test.tsx +++ b/packages/oidc-provider/src/__tests__/oidc-provider.test.tsx @@ -10,6 +10,15 @@ import * as utils from "../utils"; vi.mock("oidc-client-ts", () => ({ UserManager: vi.fn(), WebStorageStateStore: vi.fn(), + Log: { + setLogger: vi.fn(), + setLevel: vi.fn(), + NONE: 0, + ERROR: 1, + WARN: 2, + INFO: 3, + DEBUG: 4, + }, InMemoryWebStorage: class InMemoryWebStorage { private storage: Map = new Map(); get length() { @@ -888,6 +897,178 @@ describe("OIDCProvider", () => { }); }); + describe("Logger Configuration", () => { + it("should call Log.setLogger when logger prop is provided", async () => { + const { Log } = await import("oidc-client-ts"); + const mockLogger = { + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + }; + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLogger).toHaveBeenCalledWith(mockLogger); + }); + }); + + it("should not call Log.setLogger when logger prop is not provided", async () => { + const { Log } = await import("oidc-client-ts"); + vi.clearAllMocks(); + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(mockUserManager.getUser).toHaveBeenCalled(); + }); + + expect(Log.setLogger).not.toHaveBeenCalled(); + }); + + it("should call Log.setLevel when logLevel prop is provided", async () => { + const { Log } = await import("oidc-client-ts"); + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLevel).toHaveBeenCalledWith(Log.DEBUG); + }); + }); + + it("should call Log.setLevel with Log.INFO", async () => { + const { Log } = await import("oidc-client-ts"); + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLevel).toHaveBeenCalledWith(Log.INFO); + }); + }); + + it("should not call Log.setLevel when logLevel prop is not provided", async () => { + const { Log } = await import("oidc-client-ts"); + vi.clearAllMocks(); + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(mockUserManager.getUser).toHaveBeenCalled(); + }); + + expect(Log.setLevel).not.toHaveBeenCalled(); + }); + + it("should call both Log.setLogger and Log.setLevel when both props are provided", async () => { + const { Log } = await import("oidc-client-ts"); + const mockLogger = { + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + }; + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLogger).toHaveBeenCalledWith(mockLogger); + expect(Log.setLevel).toHaveBeenCalledWith(Log.WARN); + }); + }); + + it("should handle Log.NONE level", async () => { + const { Log } = await import("oidc-client-ts"); + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLevel).toHaveBeenCalledWith(Log.NONE); + }); + }); + + it("should handle Log.ERROR level", async () => { + const { Log } = await import("oidc-client-ts"); + + render( + +
Test
+
, + ); + + await waitFor(() => { + expect(Log.setLevel).toHaveBeenCalledWith(Log.ERROR); + }); + }); + }); + describe("useAuth hook", () => { it("should throw error when used outside OIDCProvider", () => { const TestComponent = () => { diff --git a/packages/oidc-provider/src/auth-provider.ts b/packages/oidc-provider/src/auth-provider.ts index cf49da7..6357ac9 100644 --- a/packages/oidc-provider/src/auth-provider.ts +++ b/packages/oidc-provider/src/auth-provider.ts @@ -1,3 +1,5 @@ +import type { ILogger } from "oidc-client-ts"; +import { Log } from "oidc-client-ts"; import React from "react"; import { Events } from "./oidc-provider"; import { StorageType } from "./token-storage"; @@ -12,5 +14,7 @@ export type AuthProviderOptions = Events & { scope?: string; useRefreshTokens?: boolean; tokenStorage?: StorageType; + logger?: ILogger; + logLevel?: Log; [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any }; diff --git a/packages/oidc-provider/src/index.ts b/packages/oidc-provider/src/index.ts index 20f8aa1..542e97c 100644 --- a/packages/oidc-provider/src/index.ts +++ b/packages/oidc-provider/src/index.ts @@ -1,3 +1,4 @@ +export { Log } from "oidc-client-ts"; export { Auth0Provider, useAuth0 } from "./auth0-provider"; export type { Auth0ProviderOptions as Auth0ProviderProps } from "./auth0-provider"; export { AzureProvider, useAzure } from "./azure-provider"; @@ -5,7 +6,7 @@ export type { AzureProviderOptions as AzureProviderProps } from "./azure-provide export { CognitoProvider, useCongito } from "./cognito-provider"; export type { CognitoProviderOptions as CognitoProviderProps } from "./cognito-provider"; export { OIDCProvider, useAuth, useAuthClient } from "./oidc-provider"; -export type { Token, Props as OIDCProviderProps, AuthProviderState } from "./oidc-provider"; +export type { AuthProviderState, Props as OIDCProviderProps, Token } from "./oidc-provider"; export { StorageTypes } from "./token-storage"; export type { TokenStorage } from "./token-storage"; export { default as withAuthenticationRequired } from "./with-authentication-required"; diff --git a/packages/oidc-provider/src/oidc-provider.tsx b/packages/oidc-provider/src/oidc-provider.tsx index 02a0554..6e71e17 100644 --- a/packages/oidc-provider/src/oidc-provider.tsx +++ b/packages/oidc-provider/src/oidc-provider.tsx @@ -1,12 +1,13 @@ import type { AccessTokenCallback, + ILogger, SigninRedirectArgs, SigninSilentArgs, SignoutRedirectArgs, SilentRenewErrorCallback, UserLoadedCallback, } from "oidc-client-ts"; -import { UserManager, UserManagerSettings, WebStorageStateStore } from "oidc-client-ts"; +import { Log, UserManager, UserManagerSettings, WebStorageStateStore } from "oidc-client-ts"; import React, { createContext, useCallback, useContext, useEffect, useReducer, useRef, useState } from "react"; import { error, initialize } from "./actions"; import reducer from "./reducer"; @@ -60,6 +61,8 @@ export type Props = Omit & Events & { children?: React.ReactNode; tokenStorage?: StorageType; + logger?: ILogger; + logLevel?: Log; }; export const OIDCProvider: React.FC = ({ @@ -70,6 +73,8 @@ export const OIDCProvider: React.FC = ({ onAccessTokenRefreshError, onRedirectCallback = defaultOnRedirectCallback, tokenStorage = StorageTypes.SessionStorage, + logger, + logLevel, ...props }) => { const [client] = useState( @@ -116,6 +121,18 @@ export const OIDCProvider: React.FC = ({ const didInitialize = useRef(false); + useEffect(() => { + if (logger) { + Log.setLogger(logger); + } + }, [logger]); + + useEffect(() => { + if (logLevel !== undefined) { + Log.setLevel(logLevel); + } + }, [logLevel]); + useEffect(() => { if (didInitialize.current) { return;