Skip to content

Commit

Permalink
feat: extract login method to config (#195)
Browse files Browse the repository at this point in the history
  • Loading branch information
Myks92 authored Oct 23, 2024
1 parent b798028 commit 3fbb90e
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 5 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ type TAuthConfig = {
// Optionally provide a callback function to run _after_ the
// user has been redirected back from the auth server
postLogin?: () => void // default: () => null
// Which method to use for login. Can be either 'redirect' or 'popup'
loginMethod: 'redirect' | 'popup' // default: 'redirect'
// Optional callback function for the 'refreshTokenExpired' event.
// You likely want to display a message saying the user need to log in again. A page refresh is enough.
onRefreshTokenExpire?: (event: TRefreshTokenExpiredEvent) => void // default: undefined
Expand Down
10 changes: 5 additions & 5 deletions src/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@ export const AuthProvider = ({ authConfig, children }: IAuthProvider) => {

function handleExpiredRefreshToken(initial = false): void {
// If it's the first page load, OR there is no sessionExpire callback, we trigger a new login
if (initial) return logIn()
if (initial) return logIn(undefined, undefined, config.loginMethod)

// TODO: Breaking change - remove automatic login during ongoing session
if (!config.onRefreshTokenExpire) return logIn()
if (!config.onRefreshTokenExpire) return logIn(undefined, undefined, config.loginMethod)

config.onRefreshTokenExpire({
login: logIn,
Expand Down Expand Up @@ -173,13 +173,13 @@ export const AuthProvider = ({ authConfig, children }: IAuthProvider) => {
// Unknown error. Set error, and log in if first page load
console.error(error)
setError(error.message)
if (initial) logIn()
if (initial) logIn(undefined, undefined, config.loginMethod)
}
// Unknown error. Set error, and log in if first page load
else if (error instanceof Error) {
console.error(error)
setError(error.message)
if (initial) logIn()
if (initial) logIn(undefined, undefined, config.loginMethod)
}
})
.finally(() => {
Expand Down Expand Up @@ -255,7 +255,7 @@ export const AuthProvider = ({ authConfig, children }: IAuthProvider) => {
}

// First page visit
if (!token && config.autoLogin) return logIn()
if (!token && config.autoLogin) return logIn(undefined, undefined, config.loginMethod)
refreshAccessToken(true) // Check if token should be updated
}, [])

Expand Down
2 changes: 2 additions & 0 deletions src/authConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function createInternalConfig(passedConfig: TAuthConfig): TInternalConfig
scope = undefined,
preLogin = () => null,
postLogin = () => null,
loginMethod = 'redirect',
onRefreshTokenExpire = undefined,
storage = 'local',
storageKeyPrefix = 'ROCP_',
Expand All @@ -30,6 +31,7 @@ export function createInternalConfig(passedConfig: TAuthConfig): TInternalConfig
scope: scope,
preLogin: preLogin,
postLogin: postLogin,
loginMethod: loginMethod,
onRefreshTokenExpire: onRefreshTokenExpire,
storage: storage,
storageKeyPrefix: storageKeyPrefix,
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export type TAuthConfig = {
logoutRedirect?: string
preLogin?: () => void
postLogin?: () => void
loginMethod: 'redirect' | 'popup'
onRefreshTokenExpire?: (event: TRefreshTokenExpiredEvent) => void
decodeToken?: boolean
autoLogin?: boolean
Expand Down Expand Up @@ -102,6 +103,7 @@ export type TInternalConfig = {
logoutRedirect?: string
preLogin?: () => void
postLogin?: () => void
loginMethod: 'redirect' | 'popup'
onRefreshTokenExpire?: (event: TRefreshTokenExpiredEvent) => void
decodeToken: boolean
autoLogin: boolean
Expand Down
1 change: 1 addition & 0 deletions tests/auth-util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const authConfig: TInternalConfig = {
refreshTokenExpiryStrategy: 'renewable',
storageKeyPrefix: 'ROCP_',
refreshWithScope: true,
loginMethod: 'redirect',
extraAuthParams: {
prompt: true,
client_id: 'anotherClientId',
Expand Down
1 change: 1 addition & 0 deletions tests/jestSetup.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ beforeEach(() => {
const location = new URL('https://www.example.com')
location.assign = jest.fn()
window.location = location
window.open = jest.fn()
})
18 changes: 18 additions & 0 deletions tests/login.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@ test('First page visit should redirect to auth provider for login', async () =>
})
})

test('First page visit should popup to auth provider for login', async () => {
render(
<AuthProvider authConfig={{ ...authConfig, loginMethod: 'popup' }}>
<AuthConsumer />
</AuthProvider>
)

await waitFor(() => {
expect(window.open).toHaveBeenCalledWith(
expect.stringMatching(
/^myAuthEndpoint\?response_type=code&client_id=myClientID&redirect_uri=http%3A%2F%2Flocalhost%2F&code_challenge=.{43}&code_challenge_method=S256&scope=someScope\+openid&state=testState/gm
),
'loginPopup',
'popup width=600 height=600'
)
})
})

test('Attempting to log in with an unsecure context should raise error', async () => {
// @ts-ignore
window.crypto.subtle.digest = undefined
Expand Down
1 change: 1 addition & 0 deletions tests/test-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const authConfig: TAuthConfig = {
scope: 'someScope openid',
decodeToken: false,
state: 'testState',
loginMethod: 'redirect',
extraLogoutParameters: {
testLogoutKey: 'logoutValue',
},
Expand Down

0 comments on commit 3fbb90e

Please sign in to comment.