3
votes

I am trying to add google authentication to my vue.js front end. This is a new project created through the CLI with typescript and component style syntax enabled (along with others) and also has a corresponding back end web server. I have been following this guide from google but I am very new to vue and gapi. I don't know how to load <script src="https://apis.google.com/js/platform.js" async defer></script> into my app or how to use it once loaded. I've found examples like this on jsfiddle and a few other examples on stack overflow and other forums, but none seem to use typescript and component style syntax or are incomplete.

App.vue

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Login</router-link>
    </div>
    <router-view />
  </div>
</template>

<style lang="scss">
</style>

Main.ts

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app");

Login.vue (View)

<template>
  <div>
    <Login />
  </div>
</template>

<script>
// @ is an alias to /src
import Login from "@/components/Login.vue";

export default {
  name: "login",
  components: {
    Login
  }
};
</script>

Login.vue (Component)

<template>
  <div>
    <button>Sign in with Google</button>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";

@Component
export default class Login extends Vue {}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
1
TypeScript is irrelevant here. You can get types for the Google apis from npm/DefinitelyTyped but the JavaScript and TypeScript logic will be identical. It's vital to understand this if you are new to TypeScript. TypeScript adds types for tooling, documentation, and verification. It does not alter or extend JavaScript language semantics. Full stop. So look at the JavaScript documentation, it is applicable and relevant by definition.Aluan Haddad
@AluanHaddad Thank you for that bit of information. I did not realize type script was completely irrelevant here. My question of how to do this still stands however. I don't understand how/where to load this google script and how to use it once that is done in the context of Vue.Montana
@Montana Do you want to use the script script src="https://apis.google.com/js/platform.js" async defer></script> or some other npm package which does the same is fine for you then I can create an example to show you how to use it.Varit J Patel
@Varit Yes, that is exactly the script I'd like to use. I'd like to just use that script and not an npm package that already does everything so that I can learn how it works a bit.Montana

1 Answers

5
votes

Well, You need to add the google sign in script inside index.html of the public folder.

Make sure you add it in the head section and without async and defer mode.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <title><%= htmlWebpackPlugin.options.title %></title>
    <script src="https://apis.google.com/js/api:client.js"></script>
  </head>
  <body>
    <noscript>
      <strong
        >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
        properly without JavaScript enabled. Please enable it to
        continue.</strong
      >
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

Now in your login.vue file

<template>
  <div>
    <button class="g-signin-button">Sign in with Google</button>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class Login extends Vue {
  clientId = "AIzaSyBRxykObiOjM7VsY_lyGcRU27q8aFeAagk";
  mounted() {
    if (!window.gapi) {
      throw new Error(
        '"https://apis.google.com/js/api:client.js" needs to be included as a <script>.'
      );
    }

    if (!this.clientId) {
      throw new Error("Client Id must be specified.");
    }

    window.gapi.load("auth2", () => {
      const auth2 = window.gapi.auth2.init({ client_id: this.clientId });
      auth2.attachClickHandler(
        this.$refs.signinBtn,
        {},
        googleUser => {
          this.$emit("success", googleUser);
        },
        error => {
          this.$emit("error", error);
          this.$emit("failure", error); // an alias
        }
      );
    });
  }
  methods() {
    function err(msg: string) {
      typeof console !== "undefined" &&
        console.error(`[g-signin-button] ${msg}`);
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.g-signin-button {
  box-sizing: border-box;
  position: relative;
  /* width: 13em;  - apply for fixed size */
  margin: 0.2em;
  padding: 0 15px 0 46px;
  border: none;
  text-align: left;
  line-height: 34px;
  white-space: nowrap;
  border-radius: 0.2em;
  font-size: 16px;
  color: #fff;
  background: #dd4b39;
}
.g-signin-button:before {
  content: "";
  box-sizing: border-box;
  position: absolute;
  top: 0;
  left: 0;
  width: 34px;
  height: 100%;

  border-right: #bb3f30 1px solid;
  background: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/14082/icon_google.png")
    6px 6px no-repeat;
}

.g-signin-button:hover,
.g-signin-button:focus {
  cursor: pointer;
  background: #e74b37;
}
</style>

Since, gapi is installed at the level of the window and to support the typescript, externam npm packages needs to be installed for the types

npm i -D @types/gapi @types/gapi.auth2

And add that to types key inside tsconfig.json

"types": ["webpack-env", "gapi", "gapi.auth2"],

Hope this helps!