Ionic Vue JS AWS Amplify Authentication CRUD Tutorial Part 1, Authentication UI Component
Tags: ionic, aws, vue, javascript
Published: 2021-04-16 08:28:52

###Getting Started
Following the directions from [Amplify Documentation](https://docs.amplify.aws/cli/start/install)
```
npm install -g @aws-amplify/cli
```
**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](https://portal.aws.amazon.com/billing/signup?redirect_url=https%3A%2F%2Faws.amazon.com%2Fregistration-confirmation#/start).

**Configure Amplify** if you havent done that before. There is a great video walkthrough or step by step instructions provided [here](https://docs.amplify.aws/cli/start/install#configure-the-amplify-cli)

### 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
```
Add authentication... just pick email and all the defaults with no additional details
```
amplify add auth
```
Once it is is done locally, push changes to the server
```
amplify push
```
### 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](https://docs.amplify.aws/ui/q/framework/vue)

Install the components, and aws-amplify
```
npm aws-amplify @aws-amplify/ui-components
```

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`
```javascript
// shims-vue.d.ts
declare module 'aws-exports'
```

Add the following code to `tsconfig.json`
```javascript
// tsconfig.json
"allowJs": true,
```
#### Amplify Components UI Issues
Create a new file in the root of the project named `vue.config.js` and add the following contents
```javascript
// 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;
        });
    }
  };
```
### Video
{% youtube cMDL7o9qHs0 %}

### 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxes3x8vof11gyql8ac4.png)

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.
```html
<!-- 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>
```

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
```javascript
// 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
  },
});
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o2iahqfhlxmjjdb5xr55.png)

```javascript
// 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");
});
```


```javascript
// 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;
        });
    }
  };
```