Serverless Authentication with AWS Amplify and Vuex Modules

Services like Auth0 and Firebase have been the go-to for serverless authentication, but now you have an option that lets you stay within the AWS Stack: AWS Amplify. Now it’s a lot easier to get some of the great AWS services on the client (securing storage with ease, Secure Lambda API calls with API Gateway, etc). Amplify has two main benefits:

  1. The Amplify-CLI will generate all the security and permissions automatically avoiding a lot of manual setup
  2. It comes with libraries to interact with the AWS stack on the client side in multiple languages and UI frameworks

You can use the Amplify Vue components on top of the core library which should handle most use cases. If you do decide to build your own components, it is probably for one of the following reasons:

  • Utilize an already loaded UI framework
  • Full customization of the experience
  • The components don’t support your requirements
  • You like to control all-the-things

Customize your own authentication components

This article will:

  1. Walk through the authentication/Cognito setup
  2. Show a Vuex module for interacting with Cognito
  3. Provide an example component to handle sign-in

How this example works

  1. Users log in with an email for a username
  2. Users must signup and confirm email address before logging in

Setting up AWS Amplify

For full customization, we will need to add our own user pool, but first use the client to set up all the permissions and services.

  1. Setup the AWS Amplify Cli (@aws-amplify/cli)
  2. Initiate your Amplify project amplify init
  3. Make sure you are in the desired AWS region
  4. Add a (temporary) Authentication/Cognito serviceamplify add auth
  5. Add any other services you want to use ie: Storage
  6. Push your project amplify push

Now we can setup AWS Cognito

  1. Login to AWS Cognito, selection the region, and Create a User Pool with the desired settings
  2. You probably will want to customize the User Pool email verification messages since this solution requires email confirmation
  3. In User Pool settings go to the App clients link and click Add another app client
  4. Create an app client but uncheck Generate client secret since this only applies to server-to-server communication:
Create and customize an app client

Setting up Amplify on the Client

Amplify will generate an aws-exports.js file but we can’t rely on it not getting overwritten, also you should add it to your .gitignore for security. In your main.js file add the amplify dependencies:

For the purpose of this demo I am placing secrets in code, never add this to your repo, use environment variables and secret storage.


Account Vuex Module Example

This Vuex module will do all the heavy lifting so your components deal with an easy API and you can easily check on the users’ authenticated state.

account.vue

When a user logs in, a timer is set to automatically refresh the token when it expires.

Vuex Module Explained

State Variables:

  • authorized A boolean you can check if a user is authorized ($store.state.account.authorized)
  • user An object of the user's information
  • loginError A string containing the Cognito response on an invalid login attempt
  • signupError A string containing the Cognito response on an invalid signup attempt
  • confirm Boolean indicating if the user wants to confirm their email address. This can happen right after signup or if a user comes back later.
  • confirmError A string containing the Cognito response on an invalid email confirmation

Module Usage:

These 3 module actions trigger the AWS Amplify Authentication/Cognito Service.

Other Actions

  • fetchUser attempts to refresh the user state from Cognito. Should only call once on application initialize, or if you want to refresh the token
  • logout will ensure the user has logged out

Handling Authentication Changes:

Most cases will require logic run when a user gets logged in or out. You can add this to main.js or app.vue then choose to redirect the user, load components, etc on change.

Fetching the JWT (JSON Web Token)

You may need to obtain the JWT for interacting with a server or API. Here is some example code to fetch it:

The state is passed to the method purely to check if the user is currently authorized, this can be handled differently.

Extending Authentication to a Server API

Very soon I will release an article on:

  • Using Axios including attaching authorization headers
  • Express middleware for authorizing API requests
  • Auto handling expired tokens

A Complete Sign-in Component Using Vuetify

This lengthy example component handles all operations on one page (login, signup, and email validation).

This would be easy to customize for your Cognito setup and port to Bootstrap/Element/whatever framework you use.

Component Notes

  • The section component is a simple card view with a title
  • I attempt to turn off browser autocomplete

Computed Confirmation Value From State.account

The computed confirmation variable tells the sign-in component if the user wants to confirm their email address (with the verification code sent). This happens when the user has just signed up or when the user has returned from checking their email for the verification code. Once verified, the user can log in.


Error Handling

There are two levels of error handling:

  1. If the field rules are not passed when submitting forms
  2. Errors passed by the Amplify library from the Cognito Service

The errors are then displayed on the components until a successful submittal.


That’s all for now, let me know if I am missing something or you want more information on anything.