ステップ・バイ・ステップでAuth0 + Vue.js + GolangでFrontend&Backend API 両方で認証するアプリ作る

f:id:yomon8:20180621205707p:plain

この記事見つけて今使っている技術にぴったりだと思って色々参考にさせていただきました。 qiita.com

ただ、認証部分がFirebaseでなくAuth0使っているので、主にその部分を変更して、自分でやってみた手順を書いてみました。

システム情報

ローカルで以下のように動くように設定してあります。特にURLはAuth0の設定でも重要なので覚えておきます。

サービス 言語 URL 備考
Frontend Vue.js http://localhost:8080 -
- - http://localhost:8080/callback Home画面
- - http://localhost:8080/callback Auth0からのCallback
Backend Golang http://localhost:50000 -
- - http://localhost:50000/public いつでもアクセス可能
- - http://localhost:50000/private JWTの検証が必要
- - http://localhost:50000/private-scoped JWTに合わせてScopeも検証も必要

Auth0の設定

それぞれの項目で以下の設定を行います。

項目 名前
API my-go-api
Application my-go-api
Database
(Connection)
MY-USER-DB
User 自身のメールアドレス

APIs

my-go-apiという名前のAPI作成します。Identifierは自身のAPIサーバーのURLを入れてますが、論理的な値なので他でも大丈夫ではあります。後の設定で使うのでメモしておきます。後でScope設定しますが、この時点ではここまでです。

f:id:yomon8:20180621172219p:plain

Applications

API作成すると同じ名前のmy-go-apiでApplicationも作成されています。

f:id:yomon8:20180621172222p:plain

まず、画面にある DomainClient ID をメモしておきます。そして以下の設定を行います。

項目
Settings > Allowed Callback URLs http://localhost:8080/callback
Show Advanced Settings > OAuth >JsonWebToken Signature Algorithm RS256

Connections

今回はConnections > DatabaseでAuth0上に作成したユーザで認証を行います。

わかりやすく、 MY-USER-DB という名前で作成します。

f:id:yomon8:20180621172229p:plain

作成したら先程作成した my-go-api のApplicationに紐付けておきます。

f:id:yomon8:20180621172232p:plain

Application側からもGoogle等の認証を外して、MY-USER-DB だけを有効化します。

f:id:yomon8:20180621184855p:plain

Users

上で作ったDatabaseにユーザを作成します。自分のメールアドレスで作ってみました。

f:id:yomon8:20180621172235p:plain

Auth0からメールが届くのでリンククリックしてVerifyします。

これでAuth0側の設定は完了です。

アプリケーション側設定

次にアプリケーション側です。まずは一回動かしてみることにします。

github.com

まずはリポジトリ落として中に入ります。この後の作業はこのリポジトリのルートディレクトリで行います。

$ git clone https://github.com/yomon8/auth0-vuejs-go.git
$ cd auth0-vuejs-go

Backend (Golang)

Backend APIサーバ設定

Backendの設定パラメータは以下のファイルにありますので、設定していきます。

vim ./api/main.go
const (
    Auth0Domain        = "yomon8.auth0.com"
    Auth0Audience      = "http://localhost:50000"
    Auth0RequiredScope = "read:messages"
)
定数 値の説明
Auth0Domain 自身のAuth0のドメイン
Auth0Audience APIのIdentifierで設定した値(この手順では変更不要)
Auth0RequiredScope 後ほど使うScope名(この手順では変更不要)
Backend APIサーバ起動

Goで直接起動する場合

$ go run ./api/main.go

Dockerで起動する場合

# 起動
$ ./start_api.sh

# 停止
$ ./stop_api.sh
Backend APIサーバ稼働確認

/publicAPI叩いて稼働確認

$ curl  http://localhost:50000/public
Hello public!

Frontend (Vue.js)

フロントエンド側は ./src/lib/auth/auth0-variables.js ファイルに設定をしていきます。

Frontend設定
export const AUTH_CONFIG = {
  clientId: "UEiX732fJmRj0KfYSjMBVt2N7RbH2Lzo",
  domain: "YourAuth0Domain.auth0.com",
  callbackUrl: "http://localhost:8080/callback",
  connection: "MY-USER-DB",
  apiurl: "http://localhost:50000",
  scope: "read:messages"
};
変数 値の説明
clientId Application my-go-api の Client ID
domain 自身のAuth0のドメイン
callbackUrl 認証のCallbackのエンドポイント(この手順では変更不要)
connection ユーザを登録したDatabase名(この手順では変更不要)
apiurl APIサーバのURL(この手順では変更不要)
scope Scopeは後で使うので上記の通りread:messages
Frontendサーバ起動

起動します。

$ npm i
$ npm run dev

動かしてみる

Frontend/Backend両方がそろったので動かしてみます。

認証無しの状態でAPIを叩く

http://localhost:8080にアクセスすると以下の画面が表示されます。login/logout ボタンとそれぞれのAPI(public/private/private-scoped)を叩けるボタンがあります。

f:id:yomon8:20180621220214p:plain

この時点ではそれぞれのボタンの結果は以下の通り認証を実装していないpublicだけが正常に動きます。

Button Message
public Hello public!
private 401 Error
private-scoped 401 Error

ログインしてみる

ログインボタンをクリックするとAuth0のlockと呼ばれるログイン画面が表示されます。

f:id:yomon8:20180621220207p:plain

ユーザ名とパスワードを入力すると認可の確認画面が出ます。この時点では何もScopeに入れていないのでこれだけです。

f:id:yomon8:20180621220210p:plain

ログインできました。

f:id:yomon8:20180621220217p:plain

ログイン後APIを叩く

ログイン後もprivate-scopedだけはエラーが出ることがわかります。これは、GolangAuth0RequiredScope の定数で設定していた、 read:messages のScopeがJWTに含まれていないため、認可が通らない状態です。

Button Message
public Hello public!
private Hello jwt validated!
private-scoped 401 Error

Scope設定

ではJWTにscopeが入る(認可)されるように、Auth0に設定します。

APIの設定でScopesのタブにて、read:messagesを追加します。

f:id:yomon8:20180621220220p:plain

Scope設定後

設定後にログアウト・ログインすると認可を求められる画面が出ます。今度はMessagesという認可対象のスコープが表示されています。

f:id:yomon8:20180621220224p:plain

これをOKしてから試すと以下のように全て上手くいくようになります。

Button Message
public Hello public!
private Hello jwt validated!
private-scoped Hello jwt and scope validated!

その他

ここまでで一通り動くようになったので、後はデバッグ等して動きのイメージを掴むと良いと思います。

AccessTocken

Auth0のAPIを利用する際のresponseType に tokenと設定するとaccess_tokenが取得できます。(id_token と設定するとid_tokenです。この例では両方設定しているので、両方取得できています。

src/lib/auth/AuthService.js

 auth0 = new auth0.WebAuth({
    domain: AUTH_CONFIG.domain,
    clientID: AUTH_CONFIG.clientId,
    redirectUri: AUTH_CONFIG.callbackUrl,
    audience: AUTH_CONFIG.apiurl,
    connection: AUTH_CONFIG.connection,
    scope: AUTH_CONFIG.scope,
    responseType: "token id_token"
  });

APIを叩く時に使っているはaccess_tockenです。

src/components/Home.vue

    apiPrivateScoped: async function() {
      try {
        let res = await axios.get("http://localhost:50000/private-scoped", {
          headers: {
            Authorization: `Bearer ${localStorage.getItem("access_token")}`
          }
        });
        this.msg = res.data;
      } catch (e) {
        this.msg = e.message;
      }
    }

JWTの確認

Chrome Developer Toolで確認できます。

f:id:yomon8:20180621222942p:plain

id_tokenaccess_tokenがありますが、Tockenの中身は、こちらのサイトにコピペすると確認できます。

jwt.io

JWTの中身には以下のような項目が設定されています。

項目 内容
iss トークンのIssuer(発行者)
sub トークンのSubject
aud トークンを消費するAudience
exp 有効期限
iat 発行時刻(Issued-At Timestamp)

参考

github.com

auth0.com