-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add /login-callback
route and optional new authProvider.handleLoginCalback()
method
#8457
Merged
+548
−4
Merged
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
5104e66
Add `login-callback` hook and `authProvider` optional new `handleLogi…
djhi e3fb9e6
Add some documentation
djhi 8810359
Rename LoginCallback to AuthCallback
djhi c58151e
Better doc wording
djhi 8d4b214
Handle previous url redirection
djhi 5bbe456
Add a test validating permissions are correctly refreshed after diffe…
djhi c80dfaf
Defaults to showing an error page when callback fail
djhi 04862c2
Fix tests
djhi 4796eac
Add stories
djhi 0a5bb04
Remove only in tests
djhi 4d6ed9b
Rename handleLoginCallback to handleCallback
djhi 04e5416
Document handleCallback in writing authProvider
djhi d01db1b
Update documentation
djhi af53503
Fix bad link
djhi 95e7041
Fix file names & exports
djhi 44c213d
Update types
djhi 4a13ce7
Fix tests
djhi b996f9f
Remove message property
djhi 9f5209f
Fix types
djhi 230d8e3
Fix build
djhi d977ff7
Rename auth callback path
djhi 0694844
Add support for previous location redirect
djhi d57138e
Update documentation
djhi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
165 changes: 165 additions & 0 deletions
165
packages/ra-core/src/auth/useHandleAuthCallback.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import * as React from 'react'; | ||
import expect from 'expect'; | ||
import { render, waitFor } from '@testing-library/react'; | ||
import { unstable_HistoryRouter as HistoryRouter } from 'react-router-dom'; | ||
import { QueryClientProvider, QueryClient } from 'react-query'; | ||
import { createMemoryHistory } from 'history'; | ||
|
||
import { useHandleAuthCallback } from './useHandleAuthCallback'; | ||
import AuthContext from './AuthContext'; | ||
import { useRedirect } from '../routing/useRedirect'; | ||
import useLogout from './useLogout'; | ||
import { AuthProvider } from '../types'; | ||
|
||
jest.mock('../routing/useRedirect'); | ||
jest.mock('./useLogout'); | ||
|
||
const redirect = jest.fn(); | ||
// @ts-ignore | ||
useRedirect.mockImplementation(() => redirect); | ||
|
||
const logout = jest.fn(); | ||
// @ts-ignore | ||
useLogout.mockImplementation(() => logout); | ||
|
||
const TestComponent = ({ customError }: { customError?: boolean }) => { | ||
const [error, setError] = React.useState<string>(); | ||
useHandleAuthCallback( | ||
customError | ||
? { | ||
onError: error => { | ||
setError(error as string); | ||
}, | ||
} | ||
: undefined | ||
); | ||
return error ? <>{error}</> : null; | ||
}; | ||
|
||
const authProvider: AuthProvider = { | ||
login: () => Promise.reject('bad method'), | ||
logout: () => { | ||
return Promise.resolve(); | ||
}, | ||
checkAuth: params => (params.token ? Promise.resolve() : Promise.reject()), | ||
checkError: params => { | ||
if (params instanceof Error && params.message === 'denied') { | ||
return Promise.reject(new Error('logout')); | ||
} | ||
return Promise.resolve(); | ||
}, | ||
getPermissions: () => Promise.reject('not authenticated'), | ||
handleCallback: () => Promise.resolve(), | ||
}; | ||
|
||
const queryClient = new QueryClient(); | ||
|
||
describe('useHandleAuthCallback', () => { | ||
afterEach(() => { | ||
redirect.mockClear(); | ||
}); | ||
|
||
it('should redirect to the home route by default when the callback was successfully handled', async () => { | ||
const history = createMemoryHistory({ initialEntries: ['/'] }); | ||
render( | ||
<HistoryRouter history={history}> | ||
<AuthContext.Provider value={authProvider}> | ||
<QueryClientProvider client={queryClient}> | ||
<TestComponent /> | ||
</QueryClientProvider> | ||
</AuthContext.Provider> | ||
</HistoryRouter> | ||
); | ||
await waitFor(() => { | ||
expect(redirect).toHaveBeenCalledWith('/'); | ||
}); | ||
}); | ||
|
||
it('should redirect to the provided route when the callback was successfully handled', async () => { | ||
const history = createMemoryHistory({ initialEntries: ['/'] }); | ||
render( | ||
<HistoryRouter history={history}> | ||
<AuthContext.Provider | ||
value={{ | ||
...authProvider, | ||
handleCallback: () => | ||
Promise.resolve({ redirectTo: '/test' }), | ||
}} | ||
> | ||
<QueryClientProvider client={queryClient}> | ||
<TestComponent /> | ||
</QueryClientProvider> | ||
</AuthContext.Provider> | ||
</HistoryRouter> | ||
); | ||
await waitFor(() => { | ||
expect(redirect).toHaveBeenCalledWith('/test'); | ||
}); | ||
}); | ||
|
||
it('should logout and not redirect to any page when the callback was not successfully handled', async () => { | ||
const history = createMemoryHistory({ initialEntries: ['/'] }); | ||
render( | ||
<HistoryRouter history={history}> | ||
<AuthContext.Provider | ||
value={{ | ||
...authProvider, | ||
handleCallback: () => Promise.reject(), | ||
}} | ||
> | ||
<QueryClientProvider client={queryClient}> | ||
<TestComponent /> | ||
</QueryClientProvider> | ||
</AuthContext.Provider> | ||
</HistoryRouter> | ||
); | ||
await waitFor(() => { | ||
expect(logout).toHaveBeenCalled(); | ||
expect(redirect).not.toHaveBeenCalled(); | ||
}); | ||
}); | ||
|
||
it('should redirect to the provided route when the callback was not successfully handled', async () => { | ||
const history = createMemoryHistory({ initialEntries: ['/'] }); | ||
render( | ||
<HistoryRouter history={history}> | ||
<AuthContext.Provider | ||
value={{ | ||
...authProvider, | ||
handleCallback: () => | ||
Promise.reject({ redirectTo: '/test' }), | ||
}} | ||
> | ||
<QueryClientProvider client={queryClient}> | ||
<TestComponent /> | ||
</QueryClientProvider> | ||
</AuthContext.Provider> | ||
</HistoryRouter> | ||
); | ||
await waitFor(() => { | ||
expect(redirect).toHaveBeenCalledWith('/test'); | ||
}); | ||
}); | ||
|
||
it('should use custom useQuery options such as onError', async () => { | ||
const history = createMemoryHistory({ initialEntries: ['/'] }); | ||
render( | ||
<HistoryRouter history={history}> | ||
<AuthContext.Provider | ||
value={{ | ||
...authProvider, | ||
handleCallback: () => | ||
Promise.resolve({ redirectTo: '/test' }), | ||
}} | ||
> | ||
<QueryClientProvider client={queryClient}> | ||
<TestComponent customError /> | ||
</QueryClientProvider> | ||
</AuthContext.Provider> | ||
</HistoryRouter> | ||
); | ||
await waitFor(() => { | ||
expect(redirect).toHaveBeenCalledWith('/test'); | ||
}); | ||
}); | ||
slax57 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit confusing. Could you elaborate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get what's confusing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why this section occurs here. It has nothing to do with the login callback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I introduce a new dedicated page to third party authentication services ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
at least a section in the Authentication introduction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the authentication introduction page