After decoupling of the frontend and backend where in Open Event Orga Server has been transformed into JSON:API Spec Compliant REST API , the front end resides in Open Event Frontend, and this blog post illustrates how the login and authentication works on Open Event Frontend using the new API.
First, we will briefly explore the UI of the login form, it’s a standard login form, with the ability to display errors in case something goes wrong. Like all forms it is stored in it’s separate component. With two fields an email and a password. Brief discussion of the UI is important since the field names will be the same ones used for fetching values making requests to the API. In case there is an error, for instance wrong credentials, it gets passed to the errorMessage property of the component. For entire code for the UI of the form, please refer to the Resources section at the end of the blog. The only relevant details which we need from the UI are the names of the fields, which are email and password respectively.And that the login button triggers the submit action of the form.
So we begin our discussion with a brief description of the package which manages the authentication in Open Event Front End. ember-simple-auth has been used to manage all the authentication needs, including maintaining the current user session. To quote it’s official documentation it helps us achieve the following goals in our project among it’s many other capabilities which are not being used here :
- it maintains a client side session and synchronises its state across multiple tabs/windows of the application
- it authorises requests to backend servers
In addition to ember-simple-auth we make use of ember-simple-auth-token which is an extension to ember-simple-auth library. It provides the token authenticator and thus handles communicating with the backend to receive a token successfully.
Next we need to configure the above two libraries, to connect to our API located at open-event-api.herokuapp.com The documentation tells us exactly what routes we need, in our case we need to make a POST request to the route /auth/session and pass in email and password in the body. The Content-Type should be specified as application/json. If everything goes well, we should receive a JWT access token in response.To configure the libraries, we specify the following in config/environment.js file.
ENV['ember-simple-auth'] = { authorizer: 'authorizer:jwt' }; ENV['ember-simple-auth-token'] = { refreshAccessTokens : false, serverTokenEndpoint : `${ENV.APP.apiHost}/auth/session`, identificationField : 'email', passwordField : 'password', tokenPropertyName : 'access_token', refreshTokenPropertyName : 'refresh_token', authorizationPrefix : 'JWT ', authorizationHeaderName : 'Authorization', headers : {} };
So we begin our discussion from the point where user has entered the credentials and presses the login button which triggers the submit action. Following is the code for the submit action and we will examine each section of it in this article.
submit() { this.onValid(() => { let credentials = this.getProperties('identification', 'password'), authenticator = 'authenticator:jwt'; this.set('errorMessage', null); this.set('isLoading', true); this.get('session') .authenticate(authenticator, credentials) .then(() => { const tokenPayload = this.get('authManager').getTokenPayload(); if (tokenPayload) { this.get('store').findRecord('user', tokenPayload.identity).then(user => { this.get('session').set('data.currentUser', user); }); } }) .catch(reason => { if (reason.hasOwnProperty('status_code') && reason.status_code === 401) { this.set('errorMessage', this.l10n.t('Your credentials were incorrect.')); } else { this.set('errorMessage', this.l10n.t('An unexpected error occurred.')); } this.set('isLoading', false); }) }); }
this.onValid() ensures that the rest of the action is executed only if the values entered by the user pass the basic form validations. Using getProperties, the values entered by the user are stored in credentials. Next, the authenticator is specified and isLoading is set to true to show the loading icon while the request is processed. And then we use the authenticate method of ember simple auth to validate the credentials. If the authentication is successful, the then clause executes and we fetch the correct user from the model using tokenPayload which contains the required information in the form of it’s identity property and set it as the current user for the session.
However if the authentication fails, the catch block executes. The API is configured to return the correct status code 401, in case the credentials were wrong, in which case the errorMessage is set to the appropriate response. The else clause handles all other cases where authentication fails and gives a generic error message. Finally the isLoading is set to false. And if the authentication was successful, the user is redirected to the index route else, stays on the same route with the error message.