1

I’m trying to implement Lock v11 in a React app and after user logs in, even though I hit the event listener and the event type is authenticated, the callback function is not getting called to process the tokens.

Here's my App.jsx where I'm both initializing Auth0 Lock and waiting for the authenticated event. Any idea why my listener is not working? To clarify it further, I put debuggers in the code. After a successful user login, I do hit the first debugger but not the second one.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Redirect, Route, Switch, withRouter } from 'react-router-dom';
import Auth0Lock from 'auth0-lock';

// Actions
import * as appActions from '../actions/app-actions';

// Components
import Home from './home/Home';
import Public from './public/Public';

class App extends Component {

    lock = new Auth0Lock('my_auth0_client_id', 'my_domain.auth0.com', {
        auth: {
            audience: 'https://my_backend_api_url/',
            redirectUrl: 'http://localhost:3000',
            responseType: 'token id_token',
            sso: false
        }
      });

    constructor(props) {

        super(props);
        this.onAuthenticated = this.onAuthenticated.bind(this);
        this.isAuthenticated = this.isAuthenticated.bind(this);

        this.onAuthenticated();
    }

    onAuthenticated() {
        debugger; // After successful login, I hit this debugger
        this.lock.on('authenticated', (authResult) => {
            debugger; // But I never hit this debugger
            let expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
            sessionStorage.setItem('access_token', authResult.accessToken);
            sessionStorage.setItem('id_token', authResult.idToken);
            sessionStorage.setItem('expires_at', expiresAt);

          });
    }

    isAuthenticated() {

        if(!sessionStorage.getItem("access_token") || !sessionStorage.getItem("id_token") || !sessionStorage.getItem("expires_at"))
            return false;

        const expiresAt = JSON.parse(localStorage.getItem('expires_at'));
        return new Date().getTime() < expiresAt;
    }

    render() {

        const isAuthenticated = this.isAuthenticated();

        return (
            <div>
                <Switch>
                    <Route exact path="/" render={props => isAuthenticated ? <Home {...props} /> : <Redirect to="/public" />} />
                    <Route path="/public">
                        <Public lock={this.lock} />
                    </Route>
                </Switch>
            </div>
        );
    }
}

function mapStateToProps(state) {

    return {
        isAuthenticated: state.app.isAuthenticated
    };
}

function mapDispatchToProps(dispatch) {

    return {

        actions: bindActionCreators(appActions, dispatch)
    };
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
Sam
  • 26,817
  • 58
  • 206
  • 383

3 Answers3

2

It's Konrad, I'm Auth0 Community Engineer, let me help you with that! Looking at this document about Lock and its first paragraph:

https://auth0.com/docs/libraries/lock/v11/configuration

it seems that you need to initialize Lock in index file and judging by this doc:

https://auth0.com/docs/libraries/lock/v11/api#on-

the listener should be placed within the same file where you initialized Lock.

  • Just posted the code that shows my initialization and listener for `authenticated` event. For some reason, after user login, the listener gets called and looks like the event type is `authenticated` but the callback function is not getting called with `authResults`. Any idea why this maybe happening? – Sam Dec 29 '19 at 07:06
0

Pull this.lock.on('authenticated'... up to index.js and make lock = new Auth0Lock... also global in index.js.

Or use the auth0 react sdk guide: https://auth0.com/docs/quickstart/spa/react/01-login

Hope that helps.

Jonathan
  • 5,736
  • 2
  • 24
  • 22
  • There are two areas that I’m struggling with here. First, I’m not sure how to have the lock.on(‘authenticated’) listener in index.js. It’s easy enough to initialize lock there but not sure how to handle the listener. Second, I need a way to pass lock down so that I can access it from my components. Not sure how to do that. Maybe use the Context API Provider approach. The app is already using Redux which could be another way to make lock accessible in components but that doesn’t seem like the right approach. Would you mind sharing some code on how to handle the index.js part? – Sam Jan 06 '20 at 11:41
  • @sam - window.lock gives you access to global init’ed in index.js and the authenticated is an event that fires whenever the user authenticates. It’s like an onClick event. You schedule it for later when the action actually happens. – Jonathan Jan 07 '20 at 15:32
  • In index.js, if you have var x = “foo”; then you can access it anywhere in any JavaScript module by prefixing x with “window”. So window.x === “foo” – Jonathan Jan 07 '20 at 15:35
0

The authLock object needs to be initialized outside the class and therefore is possible to declare it not only in the index.

Yet, to use the logout in multiple pages/components you need to expose it. I prefer the redux more than global variable.

If you need to use the object in a single place:

const authLockOptions: Auth0LockConstructorOptions = {
  allowSignUp: false,
  languageDictionary: { title: 'empty if you don't want title' },
  theme: {
    primaryColor: '#333435',
    logo: 'https://your-logo-url.com',
  },
};
const domain = process.env.AUTH0_DOMAIN || '';
const clientId = process.env.AUTH0_CLIENT_ID || '';
const authLock = new Auth0Lock(clientId, domain, authLockOptions);

export class LoginViewClass extends React.Component<LoginViewProps<BaseProps>, LoginViewState> {
  private authLock?: Auth0LockStatic;

  constructor(props: LoginViewProps<BaseProps>) {
    super(props);

    this.initializeAuthentication();
  }

  private initializeAuthentication = (): void => {
    authLock.on('authenticated', (authResult: any) => {
      // call authentication function;
    });

    authLock.show();
  };

  render(): React.ReactNode {
    return <div className='login'></div>;
  }
}

or, if you need to call the logout from multiple places

// if you are using TypeScript, Auth0LockStatic is the typeof authLock object
export type YourStore = {
  authLock: Auth0LockStatic;
  // ...
};

// start the authLock when creating the DefaultStore
export const DefaultStore: YourStore = {
  authLock: new Auth0Lock(clientId, domain, authLockOptions),
  // ...
};

// in case you use reducer
const rootReducer = combineReducers({
  // other reducers
  authLock: (state = {}) => state,
});

After adding it to the redux store, either you connect with mapStateToProps (react-redux) or useSelector (react-redux) and use it as you please.

  authLock.on('authenticated', (authResult: any) => {
    // add your authentication functionality like dispatching the authentication
  });

  authLock.show();
Daniel Santana
  • 1,493
  • 20
  • 19