Skip to content
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

[SDK-1582] Normalize the auth0 error and add error handling to the basic example #10

Merged
merged 1 commit into from
May 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,15 @@ import React from 'react';
import { useAuth0 } from '@auth0/auth0-react';

function App() {
const { isLoading, isAuthenticated, user, login, logout } = useAuth0();
const { isLoading, isAuthenticated, error, user, login, logout } = useAuth0();

if (isLoading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Oops... {error.message}</div>;
}

if (isAuthenticated) {
return (
<div>
Expand Down
12 changes: 8 additions & 4 deletions __tests__/auth-provider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,17 @@ describe('Auth0Provider', () => {
});

it('should handle other errors when getting token', async () => {
getTokenSilently.mockRejectedValue({ error: '__test_error__' });
getTokenSilently.mockRejectedValue({ error_description: '__test_error__' });
const wrapper = createWrapper();
const { waitForNextUpdate, result } = renderHook(
() => useContext(Auth0Context),
{ wrapper }
);
await waitForNextUpdate();
expect(getTokenSilently).toHaveBeenCalled();
expect(result.current.error).toStrictEqual({ error: '__test_error__' });
expect(() => {
throw result.current.error;
}).toThrowError('__test_error__');
expect(result.current.isAuthenticated).toBe(false);
});

Expand All @@ -115,15 +117,17 @@ describe('Auth0Provider', () => {

it('should handle redirect callback errors', async () => {
window.history.pushState({}, document.title, '/?error=__test_error__');
handleRedirectCallback.mockRejectedValue('__test_error__');
handleRedirectCallback.mockRejectedValue(new Error('__test_error__'));
const wrapper = createWrapper();
const { waitForNextUpdate, result } = renderHook(
() => useContext(Auth0Context),
{ wrapper }
);
await waitForNextUpdate();
expect(handleRedirectCallback).toHaveBeenCalled();
expect(result.current.error).toStrictEqual('__test_error__');
expect(() => {
throw result.current.error;
}).toThrowError('__test_error__');
});

it('should handle redirect and call a custom handler', async () => {
Expand Down
27 changes: 26 additions & 1 deletion __tests__/utils.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { defaultOnRedirectCallback, hasAuthParams } from '../src/utils';
import {
defaultOnRedirectCallback,
hasAuthParams,
loginError,
} from '../src/utils';

describe('utils hasAuthParams', () => {
it('should recognise the code param', async () => {
Expand Down Expand Up @@ -47,3 +51,24 @@ describe('utils defaultOnRedirectCallback', () => {
expect(window.location.href).toBe('https://www.example.com/foo');
});
});

describe('utils loginError', () => {
it('should return the original error', async () => {
const error = new Error('__test_error__');
expect(loginError(error)).toBe(error);
});

it('should convert an OAuth error to a JS error', async () => {
const error = { error_description: '__test_error__' };
expect(() => {
throw loginError(error);
}).toThrowError('__test_error__');
});

it('should convert a ProgressEvent error to a JS error', async () => {
const error = new ProgressEvent('error');
expect(() => {
throw loginError(error);
}).toThrowError('Login failed');
});
});
4 changes: 1 addition & 3 deletions src/auth0-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ export interface Auth0ContextInterface extends AuthState {
/**
* Get an access token.
*/
getToken: (
options?: GetTokenSilentlyOptions
) => Promise<{ [key: string]: unknown }>;
getToken: (options?: GetTokenSilentlyOptions) => Promise<string>;

/**
* Login in with a redirect.
Expand Down
12 changes: 8 additions & 4 deletions src/auth0-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import React, {
} from 'react';
import { Auth0Client, Auth0ClientOptions } from '@auth0/auth0-spa-js';
import Auth0Context from './auth0-context';
import { AppState, defaultOnRedirectCallback, hasAuthParams } from './utils';
import {
AppState,
defaultOnRedirectCallback,
loginError,
hasAuthParams,
} from './utils';
import { reducer } from './reducer';
import { initialAuthState } from './auth-state';

Expand Down Expand Up @@ -37,7 +42,7 @@ const Auth0Provider = ({
dispatch({ type: 'INITIALISED', isAuthenticated, user });
} catch (error) {
if (error.error !== 'login_required') {
dispatch({ type: 'ERROR', error });
dispatch({ type: 'ERROR', error: loginError(error) });
} else {
dispatch({ type: 'INITIALISED', isAuthenticated: false });
}
Expand All @@ -49,8 +54,7 @@ const Auth0Provider = ({
<Auth0Context.Provider
value={{
...state,
getToken: (opts): Promise<{ [key: string]: unknown }> =>
client.getTokenSilently(opts),
getToken: (opts): Promise<string> => client.getTokenSilently(opts),
login: (opts): Promise<void> => client.loginWithRedirect(opts),
logout: (opts): void => client.logout(opts),
}}
Expand Down
9 changes: 9 additions & 0 deletions src/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,12 @@ export const defaultOnRedirectCallback = (appState?: AppState): void => {
appState?.redirectTo || window.location.pathname
);
};

export const loginError = (
error: Error | { error_description: string } | ProgressEvent
): Error =>
error instanceof Error
? error
: new Error(
'error_description' in error ? error.error_description : 'Login failed'
);