Repository: soofstad/react-oauth2-pkce (ts)

Issue:
💡 [Feature] - Allow for passing arbitrary arguments to `logOut()`
### Summary

`logOut()` should support the same "additionalParameters" as `logIn()` does. As not all parameters needed can be statically set in the authConfig object

### Basic Example

nil

### Drawbacks

nil


### Unresolved questions

_No response_

### Implementation PR

_No response_

### Reference Issues

_No response_

Pull request description:
Feat/additional logout params
## What does this pull request change?
- Feature to pass arbitrary parameters to "logOut()"

## Why is this pull request needed?
See #158 and #156

## Issues related to this change
closes #158 

Patch:
diff --git a/README.md b/README.md
index c3db303..caf6266 100644
--- a/README.md
+++ b/README.md
@@ -84,7 +84,7 @@ interface IAuthContext {
   logIn: (state?: string, additionalParameters?: { [key: string]: string | boolean | number }) => void
   // Function to trigger logout from authentication provider. You may provide optional 'state', and 'logout_hint' values.
   // See https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout for details.
-  logOut: (state?: string, logoutHint?: string) => void
+  logOut: (state?: string, logoutHint?: string, additionalParameters?: { [key: string]: string | boolean | number }) => void
   // Keeps any errors that occured during login, token fetching/refreshing, decoding, etc.. 
   error: string | null
   // The idToken, if it was returned along with the access token
diff --git a/src/AuthContext.tsx b/src/AuthContext.tsx
index e685ba4..4cc93b5 100644
--- a/src/AuthContext.tsx
+++ b/src/AuthContext.tsx
@@ -1,5 +1,10 @@
 import React, { createContext, useEffect, useMemo, useRef, useState } from 'react'
 import useBrowserStorage from './Hooks'
+import { createInternalConfig } from './authConfig'
+import { fetchTokens, fetchWithRefreshToken, redirectToLogin, redirectToLogout, validateState } from './authentication'
+import { decodeJWT } from './decodeJWT'
+import { FetchError } from './errors'
+import { FALLBACK_EXPIRE_TIME, epochAtSecondsFromNow, epochTimeIsPast, getRefreshExpiresIn } from './timeUtils'
 import {
   IAuthContext,
   IAuthProvider,
@@ -8,12 +13,7 @@ import {
   TRefreshTokenExpiredEvent,
   TTokenData,
   TTokenResponse,
-} from './Types'
-import { createInternalConfig } from './authConfig'
-import { fetchTokens, fetchWithRefreshToken, redirectToLogin, redirectToLogout, validateState } from './authentication'
-import { decodeJWT } from './decodeJWT'
-import { FetchError } from './errors'
-import { FALLBACK_EXPIRE_TIME, epochAtSecondsFromNow, epochTimeIsPast, getRefreshExpiresIn } from './timeUtils'
+} from './types'
 
 export const AuthContext = createContext<IAuthContext>({
   token: '',
@@ -73,10 +73,11 @@ export const AuthProvider = ({ authConfig, children }: IAuthProvider) => {
     setLoginInProgress(false)
   }
 
-  function logOut(state?: string, logoutHint?: string) {
+  function logOut(state?: string, logoutHint?: string, additionalParameters?: TPrimitiveRecord) {
     clearStorage()
     setError(null)
-    if (config?.logoutEndpoint && token) redirectToLogout(config, token, refreshToken, idToken, state, logoutHint)
+    if (config?.logoutEndpoint && token)
+      redirectToLogout(config, token, refreshToken, idToken, state, logoutHint, additionalParameters)
   }
 
   function logIn(state?: string, additionalParameters?: TPrimitiveRecord) {
diff --git a/src/authConfig.ts b/src/authConfig.ts
index b7c63ac..0464372 100644
--- a/src/authConfig.ts
+++ b/src/authConfig.ts
@@ -1,4 +1,4 @@
-import { TAuthConfig, TInternalConfig } from './Types'
+import { TAuthConfig, TInternalConfig } from './types'
 
 function stringIsUnset(value: string | null | undefined) {
   const unset = ['', undefined, null]
diff --git a/src/authentication.ts b/src/authentication.ts
index 9604964..32555e4 100644
--- a/src/authentication.ts
+++ b/src/authentication.ts
@@ -1,3 +1,5 @@
+import { postWithXForm } from './httpUtils'
+import { generateCodeChallenge, generateRandomString } from './pkceUtils'
 import {
   TInternalConfig,
   TPrimitiveRecord,
@@ -5,9 +7,7 @@ import {
   TTokenRequestForRefresh,
   TTokenRequestWithCodeAndVerifier,
   TTokenResponse,
-} from './Types'
-import { postWithXForm } from './httpUtils'
-import { generateCodeChallenge, generateRandomString } from './pkceUtils'
+} from './types'
 
 const codeVerifierStorageKey = 'PKCE_code_verifier'
 const stateStorageKey = 'ROCP_auth_state'
@@ -121,7 +121,8 @@ export function redirectToLogout(
   refresh_token?: string,
   idToken?: string,
   state?: string,
-  logoutHint?: string
+  logoutHint?: string,
+  additionalParameters?: TPrimitiveRecord
 ) {
   const params = new URLSearchParams({
     token: refresh_token || token,
@@ -130,6 +131,7 @@ export function redirectToLogout(
     post_logout_redirect_uri: config.logoutRedirect ?? config.redirectUri,
     ui_locales: window.navigator.languages.join(' '),
     ...config.extraLogoutParameters,
+    ...additionalParameters,
   })
   if (idToken) params.append('id_token_hint', idToken)
   if (state) params.append('state', state)
diff --git a/src/decodeJWT.ts b/src/decodeJWT.ts
index d23f70f..5bfc0e9 100644
--- a/src/decodeJWT.ts
+++ b/src/decodeJWT.ts
@@ -1,4 +1,4 @@
-import { TTokenData } from './Types'
+import { TTokenData } from './types'
 
 /**
  * Decodes the base64 encoded JWT. Returns a TToken.
diff --git a/src/httpUtils.ts b/src/httpUtils.ts
index b3e2883..d6213cd 100644
--- a/src/httpUtils.ts
+++ b/src/httpUtils.ts
@@ -1,5 +1,5 @@
-import { TTokenRequest } from './Types'
 import { FetchError } from './errors'
+import { TTokenRequest } from './types'
 
 function buildUrlEncodedRequest(request: TTokenRequest): string {
   let queryString = ''
diff --git a/src/index.ts b/src/index.ts
index 40041e9..cf2c777 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -4,4 +4,4 @@ export type {
   IAuthProvider,
   IAuthContext,
   TRefreshTokenExpiredEvent,
-} from './Types'
+} from './types'
diff --git a/src/timeUtils.ts b/src/timeUtils.ts
index ce8ed6f..43b1d82 100644
--- a/src/timeUtils.ts
+++ b/src/timeUtils.ts
@@ -1,4 +1,4 @@
-import { TTokenResponse } from './Types'
+import { TTokenResponse } from './types'
 export const FALLBACK_EXPIRE_TIME = 600 // 10minutes
 
 // Returns epoch time (in seconds) for when the token will expire
diff --git a/src/Types.ts b/src/types.ts
similarity index 97%
rename from src/Types.ts
rename to src/types.ts
index 119a01e..fd5f214 100644
--- a/src/Types.ts
+++ b/src/types.ts
@@ -42,7 +42,7 @@ export interface IAuthProvider {
 export interface IAuthContext {
   token: string
   logIn: (state?: string, additionalParameters?: TPrimitiveRecord) => void
-  logOut: (state?: string, logoutHint?: string) => void
+  logOut: (state?: string, logoutHint?: string, additionalParameters?: TPrimitiveRecord) => void
   /** @deprecated Use `logIn` instead */
   login: (state?: string, additionalParameters?: TPrimitiveRecord) => void
   error: string | null


Test patch:
diff --git a/tests/auth-util.test.ts b/tests/auth-util.test.ts
index 6496607..c94ccda 100644
--- a/tests/auth-util.test.ts
+++ b/tests/auth-util.test.ts
@@ -1,8 +1,8 @@
-import { TInternalConfig } from '../src/Types'
 import { fetchWithRefreshToken } from '../src/authentication'
 import { decodeJWT } from '../src/decodeJWT'
 import { FetchError } from '../src/errors'
 import { epochAtSecondsFromNow, epochTimeIsPast } from '../src/timeUtils'
+import { TInternalConfig } from '../src/types'
 
 const authConfig: TInternalConfig = {
   autoLogin: false,
diff --git a/tests/get_token.test.tsx b/tests/get_token.test.tsx
index b5ebe2f..b159a35 100644
--- a/tests/get_token.test.tsx
+++ b/tests/get_token.test.tsx
@@ -1,7 +1,7 @@
 import { render, waitFor } from '@testing-library/react'
 import React from 'react'
 import { AuthProvider } from '../src'
-import { TTokenResponse } from '../src/Types'
+import { TTokenResponse } from '../src/types'
 import { AuthConsumer, authConfig } from './test-utils'
 
 // @ts-ignore