Ionic Vue JS AWS Amplify Authentication CRUD Tutorial Part 1, Authentication UI Component

Aaron K Saunders - Apr 16 '21 - - Dev Community

Getting Started

Following the directions from Amplify Documentation

npm install -g @aws-amplify/cli
Enter fullscreen mode Exit fullscreen mode

Create AWS Account. If you don’t already have an AWS account, you’ll need to create one in order to follow the steps outlined in this tutorial.

Configure Amplify if you havent done that before. There is a great video walkthrough or step by step instructions provided here

Workflow for Adding Authentication

Initialize the project for use with amplify. This project is the base Ionic Vue Application built from the cli using the blank template.

amplify init
Enter fullscreen mode Exit fullscreen mode

Add authentication... just pick email and all the defaults with no additional details

amplify add auth
Enter fullscreen mode Exit fullscreen mode

Once it is is done locally, push changes to the server

amplify push
Enter fullscreen mode Exit fullscreen mode

Adding Authentication UI

For the authentication UI we are going to use the Amplify Authentication UI Component which you can find more information about here

Install the components, and aws-amplify

npm aws-amplify @aws-amplify/ui-components
Enter fullscreen mode Exit fullscreen mode

There were some changes needed to get the components to work since they are custom components and also to get the code to compile since we are using javascript.

Addressing Javascript Issues

Add the following code to shims-vue.d.ts

// shims-vue.d.ts
declare module 'aws-exports'
Enter fullscreen mode Exit fullscreen mode

Add the following code to tsconfig.json

// tsconfig.json
"allowJs": true,
Enter fullscreen mode Exit fullscreen mode

Amplify Components UI Issues

Create a new file in the root of the project named vue.config.js and add the following contents

// vue.config.js
module.exports = {
    chainWebpack: config => {
      config.module
        .rule('vue')
        .use('vue-loader')
        .tap(options => {
          options.compilerOptions = {
            ...(options.compilerOptions || {}),
            isCustomElement: tag => tag.startsWith('amplify-')
          };
          return options;
        });
    }
  };
Enter fullscreen mode Exit fullscreen mode

Video

Adding Amplify Components To Application

This is covered in depth, in the video I have listed below the final source code changes in the project.

Alt Text

For the template, we have wrapped the whole page with the amplify-authenticator component and set the username-alias to email since that is what we specified in the setup of authentication. The contents of the page will only show when there is an authenticated user session

You can also see that we added a footer with the logout functionality. The footer contains the amplify-sign-out component which displays a logout button.

<!-- script section of Home.vue -->
<template>
  <!-- amplify-ui -->
  <amplify-authenticator username-alias="email">
    <ion-page>
      <ion-header :translucent="true">
        <ion-toolbar>
          <ion-title>HOME</ion-title>
        </ion-toolbar>
      </ion-header>
      <ion-content :fullscreen="true" class="ion-padding">
        <p>LOGGED IN</p>
        <p>{{ user?.attributes?.email }}</p>
      </ion-content>
      <ion-footer class="ion-padding">
        <amplify-sign-out></amplify-sign-out>
      </ion-footer>
    </ion-page>
    <!-- [end] amplify-ui -->
  </amplify-authenticator>
</template>
Enter fullscreen mode Exit fullscreen mode

For the script section, we listen for authentication events to see if we have an authenticated user in onMounted. We save the unsubscribeAuth value so we can cleanup when the component is unmounted

// script section of Home.vue
import {
  IonContent,
  IonPage,
  IonTitle,
  IonToolbar,
  IonHeader,
  IonFooter
} from "@ionic/vue";
import { defineComponent, onMounted, onUnmounted, ref } from "vue";
import { onAuthUIStateChange } from "@aws-amplify/ui-components";

export default defineComponent({
  name: "Home",
  setup() {
    let unsubscribeAuth: any = null;
    const curAuthState = ref<any>(null);
    const user = ref<any>(null);

    onMounted(() => {
      unsubscribeAuth = onAuthUIStateChange((authState, authData) => {
        curAuthState.value = authState;
        user.value = authData;
      });
    });

    onUnmounted(() => {
      unsubscribeAuth();
    });

    return {
      user,
    };
  },
  components: {
    IonContent,
    IonPage,
    IonTitle,
    IonToolbar,
    IonHeader,
    IonFooter
  },
});
Enter fullscreen mode Exit fullscreen mode

Alt Text

// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";

import { IonicVue } from "@ionic/vue";

/* Core CSS required for Ionic components to work properly */
import "@ionic/vue/css/core.css";

/* Basic CSS for apps built with Ionic */
import "@ionic/vue/css/normalize.css";
import "@ionic/vue/css/structure.css";
import "@ionic/vue/css/typography.css";

/* Optional CSS utils that can be commented out */
import "@ionic/vue/css/padding.css";
import "@ionic/vue/css/float-elements.css";
import "@ionic/vue/css/text-alignment.css";
import "@ionic/vue/css/text-transformation.css";
import "@ionic/vue/css/flex-utils.css";
import "@ionic/vue/css/display.css";

/* Theme variables */
import "./theme/variables.css";

/* AMPLIFY */
import {
  applyPolyfills,
  defineCustomElements,
} from "@aws-amplify/ui-components/loader";
import Amplify from "aws-amplify";
import awsconfig from "./aws-exports";

Amplify.configure(awsconfig);

applyPolyfills().then(() => {
  defineCustomElements(window);
});

const app = createApp(App)
  .use(IonicVue)
  .use(router);

app.config.isCustomElement = (tag) => tag.startsWith("amplify-");

router.isReady().then(() => {
  app.mount("#app");
});
Enter fullscreen mode Exit fullscreen mode
// vue.config.js
module.exports = {
    chainWebpack: config => {
      config.module
        .rule('vue')
        .use('vue-loader')
        .tap(options => {
          options.compilerOptions = {
            ...(options.compilerOptions || {}),
            isCustomElement: tag => tag.startsWith('amplify-')
          };
          return options;
        });
    }
  };
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .