Skip to content

Commit

Permalink
Normalize the auth0 error and add error handling to the basic example (
Browse files Browse the repository at this point in the history
…#10)

And fix the getToken return type
  • Loading branch information
adamjmcgrath authored May 19, 2020
1 parent bfc0d73 commit 32248fa
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 13 deletions.
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'
);

0 comments on commit 32248fa

Please sign in to comment.