VuePressサイトをAuth0で認証すーる


# はじめに

[前回](https://qiita.com/SatoshiGachiFujimoto/items/19848ed27a0fafa7273c)はAzure Static Web AppsでVuePressサイトを作成しました。
今回はAuth0で認証してみたいと思います。

参考にしたのはこれ
https://auth0.com/blog/vuepress-authentication/
https://auth0.com/blog/complete-guide-to-vue-user-authentication/

# 開発環境
- Auth0
- Azure
- Node.js
- GitHub
- Windows 10 PC

# 導入
1．[前回](https://qiita.com/SatoshiGachiFujimoto/items/19848ed27a0fafa7273c)を参考にVuePressサイトを作る

.github
.gitignore
以外は全部消してOK、最初からやっていく

2．Node.jsのコマンドプロンプトから初期化、vuepress、auth0プラグインのインストール

~~~cmd
cd vuepress-static-app
npm init -y
npm install --save-dev vuepress
npm install @auth0/auth0-spa-js
~~~


3．package.jsonの編集（"scripts"の部分）

~~~package.json
{
  "name": "vuepress-static-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "vuepress build",
    "dev": "vuepress dev",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/SatoshiRobatoFujimoto/vuepress-static-app.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/SatoshiRobatoFujimoto/vuepress-static-app/issues"
  },
  "homepage": "https://github.com/SatoshiRobatoFujimoto/vuepress-static-app#readme",
  "devDependencies": {
    "vuepress": "^1.8.2"
  },
  "dependencies": {
    "@auth0/auth0-spa-js": "^1.15.0"
  }
}
~~~

4．ファイル構成は次のようになっている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/055aca02-fc87-65d6-0cc3-30f2be0e81f5.png)

5．.vuepress/config.jsを作成

~~~config.js
module.exports = {
    title: "My Documentation Site",
    description: "This is going to be awesome!",
    themeConfig: {
      nav: [
        { text: "Home", link: "/" },
        { text: "About", link: "/about/" }
      ]
    }
  };
~~~

6．Auth0アプリケーションを作成

[Auth0](https://auth0.com/jp)に登録、ログイン

ダッシュボードのActivityからCREATE APPLICATIONボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/6ff3bb2b-2514-a0e9-cd08-43dc8aa18bb9.png)

アプリ名を入れて、Single Page Web Applicationsを選び、CREATEする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/64303062-122e-c126-27dd-52a56b7d6a03.png)

アプリのSettingsからDomain、Client IDをメモしておく。あとで使う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/a7762664-63e0-efe5-1a4a-51edac66b77c.png)

Allowed Callback URLs, Allowed Logout URLs, Allowed Web Origins, Allowed Origins (CORS) に http://localhost:8080 を入力する。本番でやるときはAzure Static Web Appsで発行されたアプリのURLにする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/96e224ac-2beb-f4d9-77b6-f7c7e9bf7c21.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/7e0506f0-0f36-26c0-7768-aab5e38205f2.png)

SAVE CHANGESで保存

6．.vuepress/auth_config.jsを作成

~~~auth_config.js
const config = {
    domain: "YOUR_AUTH0_DOMAIN",
    clientId: "YOUR_CLIENT_ID"
  };
  
  export default config;
~~~

YOUR_AUTH0_DOMAINとYOUR_CLIENT_IDには先ほどメモしたものを入れる。GitHubにアップロードするのでリポジトリはPrivateにしておく。本来は環境変数とかで設定した方がいいと思う。（.gitignoreでpushしないように設定もしたほうがいい）

7．.vuepress/index.jsを作成

~~~index.js
import config from "./auth_config";
import createAuth0Client from "@auth0/auth0-spa-js";

async function createClient() {
  let auth0Client = await createAuth0Client({
    domain: config.domain,
    client_id: config.clientId
  });

  return auth0Client;
}

async function loginWithPopup(client, options) {
  try {
    await client.loginWithPopup(options);
  } catch (e) {
    // eslint-disable-next-line
    console.error(e);
  }
}

function logout(client) {
  return client.logout();
}

const auth = {
  createClient,
  loginWithPopup,
  logout
};

export default auth;
~~~

※実行時に、createAuth0Clientがないと怒られたので、@auth0/auth0-spa-jsプラグインのインストールとインポートが必要だった

8．.vuepress/enhanceApp.jsを作成

~~~enhanceApp.js
if (typeof window !== "undefined")
    window.global = window;
~~~

※実行時に ReferenceError: global is not defined vuepress というエラーがでたので対応（ https://github.com/vuejs/vuepress/issues/1434 ）

9．.vuepress/components/LoginButton.vueを作成

~~~LoginButton.vue
<template>
    <button @click="login()">Login</button>
</template>

<script>
import auth from "../";
export default {
    props : ['client'],
    methods : {
        async login () {
            await auth.loginWithPopup(this.client);

            this.$emit('login-complete');
        }
    }
}
</script>
~~~

10．.vuepress/components/LogoutButton.vueを作成

~~~LogoutButton.vue
<template>
    <button @click="logout()">Log Out</button>
</template>

<script>
import auth from "../";
export default {
    props : ['client'],
    methods : {
        async logout () {

            await auth.logout(this.client);
        }
    }
}
</script>
~~~

11．README.mdを作成

~~~README.md
---
home: true
footer: Made by Auth0 User with ❤️
---

<template>
  <div class="main-content">
    <div v-if="user">
      <p align="center">
        Hi {{user.email}}, Welcome to the Vuepress Blog
      </p>
      <p align="center">
        <LogoutButton :client="auth0client" />
      </p>
    </div>
    <div v-else>
      <p align="center">
        You are currently not logged-in to the Application. Please use the login button below to sign in
      </p>
      <p align="center">
        <LoginButton :client="auth0client" @login-complete="getUser()" />
      </p>
    </div>
  </div>

</template>

<script>
import auth from "./.vuepress";
import LoginButton from "./.vuepress/components/LoginButton";
import LogoutButton from "./.vuepress/components/LogoutButton";

export default {
  data() {
    return {
      auth0client : null,
      user : null
    }
  },
  async mounted(){
    this.auth0client = await auth.createClient();

    this.user = await this.auth0client.getUser();
  },
  methods : {
    async login () {
      await auth.loginWithPopup(this.auth0client);
    },
    async getUser(){
      this.user = await this.auth0client.getUser();
    }
  }
}
</script>
~~~

12．npm run devでアプリを起動、 http://localhost:8080 を開き、確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/e3e49ea2-c72a-1d40-7a6a-361614a2b2eb.png)

13．ログインボタンを押すとAuth0のログイン画面が出てくる。ここから誰でもSign Up、Log Inすることが可能。きたこれ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/03ae350c-4278-55df-004e-bcae24db2e2d.png)

14．ログインが完了すると、ログインした人しか見れないページになっている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/2b5e6d96-3167-6ab6-5605-d6340a77e058.png)

15．サインアップさせたくない場合は、Auth0のAuthenticationからDisable Sign Upsをオンにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/19708755-f936-870c-6634-737c624d8110.png)

するとサインアップが消えている！すごい！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/c90bdd15-2f26-b4f4-35b2-a9579c7542fe.png)

サインアップできないようにしたら、Auth0のUsers画面からCREATE USERで追加したり、削除ができる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/9f0634b4-2309-fc40-6d66-0e8cb1886886.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/27b76310-30b1-8e95-b607-10f847512fb3.png)

16．ApplicationsのConnectionsタブから、DatabaseもしくはSocialからのログインをオンオフできる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/13a84b2d-c481-fc3c-c67b-86805657d89b.png)

|すべてオフ|Socialのみ|Databaseのみ|
|:--|:--|:--|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/c49f70f8-b5d8-b109-ff67-4b46e29b7fb9.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/c8428859-843c-dcd1-ffa7-e86ab652ae02.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/f1480c46-b983-ffe5-1250-0565a5ef8246.png)|

社内ドキュメントに使う予定なのでDatabaseのみとした

17．ログインできるメールアドレスの制限はAuth PiplineのRulesからCREATE、Access ControlのWhitelistを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/fa7955b5-b408-a64f-8b23-2545bcd69b40.png)

Ruleを編集し、whitelistにログインを許可するメールアドレスを指定する

~~~js
function userWhitelist(user, context, callback) {
  // Access should only be granted to verified users.
  if (!user.email || !user.email_verified) {
    return callback(new UnauthorizedError('Access denied.'));
  }

  const whitelist = ['YOUR EMAIL ADDRESS']; //authorized users
  const userHasAccess = whitelist.some(function (email) {
    return email === user.email;
  });

  if (!userHasAccess) {
    return callback(new UnauthorizedError('Access denied.'));
  }

  callback(null, user, context);
}
~~~

18．GitHubにpush

~~~
git status
git add .
git commit -m "add Auth0"
git push
~~~

19．Azure Static Web Appsで発行されたURLでアプリの確認ができたら完成（Allowed Callback URLs, Allowed Logout URLs, Allowed Web Origins, Allowed Origins (CORS)の設定を忘れずに！）

VuePressで特定ユーザーのみログイン可能な社内ドキュメントサイト完成！