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

Initialized flag on useAuth0 hook #561

Merged
merged 7 commits into from
Jan 26, 2023
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
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,22 +274,33 @@ import {useAuth0} from 'react-native-auth0';

#### Login

Use the `authorize` method to redirect the user to the Auth0 [Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login) page for authentication. The `user` property is populated with details about the authenticated user.
Use the `authorize` method to redirect the user to the Auth0 [Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login) page for authentication.

If `user` is `null`, no user is currently authenticated.
- The `isLoading` property is set to true once the authentication state of the user is known to the SDK.
- The `user` property is populated with details about the authenticated user. If `user` is `null`, no user is currently authenticated.
- The `error` property is populated if any error occurs.

```js
const Component = () => {
const {authorize, user} = useAuth0();
const {authorize, user, isLoading, error} = useAuth0();

const login = async () => {
await authorize();
};

if(isLoading) {
return (
<View>
<Text>SDK is Loading</Text>
</View>
)
}

return (
<View>
{!user && <Button onPress={login} title="Log in" />}
{user && <Text>Logged in as {user.name}</Text>}
{error && <Text>{error.message}</Text>}
</View>
);
};
Expand Down
36 changes: 36 additions & 0 deletions src/hooks/__tests__/use-auth0.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,41 @@ describe('The useAuth0 hook', () => {
expect(result.current.clearSession).toBeDefined();
});

it('isLoading is true until initialization finishes', async () => {
const {result, waitForNextUpdate} = renderHook(() => useAuth0(), {wrapper});
expect(result.current.isLoading).toBe(true);

await waitForNextUpdate();
expect(mockAuth0.credentialsManager.getCredentials).not.toBeCalled();
expect(mockAuth0.credentialsManager.hasValidCredentials).toBeCalledTimes(1);
expect(result.current.user).toBeNull();
expect(result.current.isLoading).toBe(false);
});

it('isLoading flag set on start up with valid credentials', async () => {
mockAuth0.credentialsManager.hasValidCredentials.mockResolvedValue(true);

const {result, waitForNextUpdate} = renderHook(() => useAuth0(), {wrapper});
expect(result.current.isLoading).toBe(true);

await waitForNextUpdate();
expect(result.current.user).not.toBeNull();
expect(result.current.isLoading).toBe(false);
});

it('isLoading flag set on when error is thrown while initializing', async () => {
const errorToThrow = new Error('Error getting credentials');
mockAuth0.credentialsManager.hasValidCredentials.mockResolvedValue(true);
mockAuth0.credentialsManager.getCredentials.mockRejectedValue(errorToThrow);

const {result, waitForNextUpdate} = renderHook(() => useAuth0(), {wrapper});
expect(result.current.isLoading).toBe(true);

await waitForNextUpdate();
expect(result.current.error).toBe(errorToThrow);
expect(result.current.isLoading).toBe(false);
});

it('does not initialize the user on start up without valid credentials', async () => {
const {result, waitForNextUpdate} = renderHook(() => useAuth0(), {wrapper});

Expand All @@ -92,6 +127,7 @@ describe('The useAuth0 hook', () => {

it('initializes the user on start up with valid credentials', async () => {
mockAuth0.credentialsManager.hasValidCredentials.mockResolvedValue(true);
mockAuth0.credentialsManager.getCredentials.mockResolvedValue(mockCredentials);

const {result, waitForNextUpdate} = renderHook(() => useAuth0(), {wrapper});

Expand Down
1 change: 1 addition & 0 deletions src/hooks/auth0-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const stub = () => {
const initialContext = {
error: null,
user: null,
isLoading: true,
authorize: stub,
clearSession: stub,
getCredentials: stub,
Expand Down
12 changes: 8 additions & 4 deletions src/hooks/auth0-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {idTokenNonProfileClaims} from '../jwt/utils';
const initialState = {
user: null,
error: null,
isLoading: true,
};

/**
Expand Down Expand Up @@ -48,10 +49,13 @@ const Auth0Provider = ({domain, clientId, children}) => {
let user = null;

if (await client.credentialsManager.hasValidCredentials()) {
const credentials = await client.credentialsManager.getCredentials();

if (credentials) {
user = getIdTokenProfileClaims(credentials.idToken);
try {
const credentials = await client.credentialsManager.getCredentials();
if (credentials) {
user = getIdTokenProfileClaims(credentials.idToken);
}
} catch (error) {
dispatch({type: 'ERROR', error});
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/hooks/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ const reducer = (state, action) => {
return {...state, error: null, user: null};

case 'ERROR':
return {...state, error: action.error};
return {...state, isLoading: false, error: action.error};

case 'INITIALIZED':
return {...state, user: action.user};
return {...state, isLoading: false, user: action.user};
}
};

Expand Down
2 changes: 2 additions & 0 deletions src/hooks/use-auth0.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Auth0Context from './auth0-context';
* @typedef {Object} Auth0ContextInterface
* @property {Object} user The user profile as decoded from the ID token after authentication
* @property {Object} error An object representing the last exception
* @property {boolean} isLoading A flag that is true until the state knows that a user is either logged in or not
* @property {Function} authorize Authorize the user using Auth0 Universal Login. See {@link WebAuth#authorize}
* @property {Function} clearSession Clears the user's web session, credentials and logs them out. See {@link WebAuth#clearSession}.
* @property {Function} getCredentials Gets the user's credentials from the native credential store. See {@link CredentialsManager#getCredentials}
Expand All @@ -20,6 +21,7 @@ import Auth0Context from './auth0-context';
* // State
* error,
* user,
* isLoading,
* // Methods
* authorize,
* clearSession,
Expand Down