Auth0のユニークな機能 - ブランディングイメージのカスタマイズ編

# はじめに
この記事は[初めてのAuth0ハンズオン](https://qiita.com/hisashiyamaguchi/items/2d0bcae052077f6ae4a4)の続編で、Auth0のユニークな機能の一つである[Universal Login Page Customization](https://auth0.com/docs/libraries/when-to-use-lock)の解説です。[Universal Login Page Customization](https://auth0.com/docs/libraries/when-to-use-lock)はログイン画面を簡単にカスタマイズしてお客様のブランドイメージを保護してユーザ様に与える印象をより良くする機能です。
**<font color="DarkOrange">この記事は解説のみのため詳細な手順は掲載していません。</font>**

# 解説
左ペインの"Universal Login"をクリック、"Login"タブをクリックして"Customize Login Page"フリップスイッチをオンにするとUniversal Loginの画面をカスタマイズすることが可能になります。

<img src="https://i.imgur.com/N6iYD8s.png" width=70%>

カスタマイズしたHTMLのサンプルコードです。

```html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Travel0 Login</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <link rel="stylesheet" href="https://d2qcgv1x1k2it7.cloudfront.net/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://d2qcgv1x1k2it7.cloudfront.net/css/v2/lock-normal-overrides.css">   
</head>

<body>
    <nav class="main-header navbar navbar-expand-md navbar-dark bg-primary fixed-top">
        <div class="container"><a href="/" class="navbar-brand mx-auto">Travel0</a></div>
    </nav>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js" crossorigin="anonymous"></script>
    <script src="https://cdn.auth0.com/js/lock/11.11/lock.min.js"></script>
    <script>
        // Decode utf8 characters properly
        var config = JSON.parse(decodeURIComponent(escape(window.atob('@@config@@'))));
        config.extraParams = config.extraParams || {};
        var connection = config.connection;
        var prompt = config.prompt || config.extraParams.prompt;
        var languageDictionary = {
            title: 'Log In'
        };
        var language;
        if (typeof config.dict === 'string') {
            language = config.dict;
        }
        var loginHint = config.extraParams.login_hint;
        var logo = 'https://d2qcgv1x1k2it7.cloudfront.net/icons/logo/travel0-green.svg'
        if (config.callbackURL.includes('.hooli.corporate.')) {
            logo = 'https://d2qcgv1x1k2it7.cloudfront.net/icons/icon-hooli-logo.png'
        }

        var lock = new Auth0Lock(config.clientID, config.auth0Domain, {
            configurationBaseUrl: config.clientConfigurationBaseUrl,
            overrides: {
                __tenant: config.auth0Tenant,
                __token_issuer: document.origin
            },
            auth: {
                redirectUrl: config.callbackURL,
                responseType: (config.internalOptions || {}).response_type ||
                    (config.callbackOnLocationHash ? 'token' : 'code'),
                params: config.internalOptions
            },
            assetsUrl: config.assetsUrl,
            allowedConnections: connection ? [connection] : null,
            rememberLastLogin: !prompt,
            language: language,
            languageDictionary: languageDictionary,
            theme: {
                logo: logo,
                primaryColor: '#03C07B'
            },
            //container: "widget",
            prefill: loginHint ? { email: loginHint, username: loginHint } : null,
            closable: false,
            initialScreen: prompt === "signup" ? "signUp" : "login",
            avatar: null,
            defaultADUsernameFromEmailPrefix: false,
            // uncomment if you want small buttons for social providers
            // socialButtonStyle: 'small'
        });

        lock.show({
            // allowedConnections: ['google-oauth2'],
        });

        var validEvents = [
          'unrecoverable_error',
          'authenticated',
          'authorization_error',
          'signin ready',
          'signup ready',
          'forgot_password ready',
          'socialOrPhoneNumber ready',
          'socialOrEmail ready',
          'vcode ready',
          'forgot_password submit',
          'signin submit',
          'signup submit',
          'socialOrPhoneNumber submit',
          'socialOrEmail submit',
          'vcode submit',
          'federated login'
        ];

        validEvents.forEach(function (e) {
          lock.on(e, function (args) {
            mixpanel && mixpanel.track(`Auth0 Lock: ${e}`, args);
          });
        });
    </script>
</body>
</html>
```

Sample Applicationでイメージを確認してみます。Applicationのトップ画面です。

<img src="https://i.imgur.com/E0nFDwO.png" width=70%>

ログイン画面です。Applicationのトップ画面と同じ画像を利用することでサイトのブランドイメージを保護できます。

<img src="https://i.imgur.com/TWi0Tl0.jpg" width=70%>

[Auth0 Lock](https://auth0.com/lock)を使わずにUniversal Loginを1からカスタマイズしてみます。
**<font color="DarkOrange">Auth0 LockはAuth0が提供しているログインウィジェットです。ログインウィジェットを出さずに画面にフォームを埋め込みたい場合はUniversal Loginを1からカスタマイズすることで可能です。</font>**
カスタマイズしたHTMLのサンプルコードです。


```html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Travel0 Login</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <link rel="stylesheet" href="https://d2qcgv1x1k2it7.cloudfront.net/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://d2qcgv1x1k2it7.cloudfront.net/css/v2/lock-normal-overrides.css">   
</head>

<body>
    <div id="root"></div>
    <script src="https://auth0japan-demo.idfirst.accounts.travel0.net/static/js/bundle.min.js"></script>
    <script>
        const config = JSON.parse(decodeURIComponent(escape(window.atob("@@config@@"))));
        new window.LoginWidget().init({
          serverURL: "https://auth0japan-demo.idfirst.accounts.travel0.net",
          logo: "https://d2qcgv1x1k2it7.cloudfront.net/icons/logo/travel0-green.svg",
          background: "https://d2qcgv1x1k2it7.cloudfront.net/images/Forest-background-2.png",
          pageConfig: config
        });
    </script>
</body>
</html>
```

ログイン画面です。Auth0 Lockのログインウィジェットは表示されずに画面に埋め込まれたフォームが表示されます。

<img src="https://i.imgur.com/cgWWBtc.png" width=70%>
<img src="https://i.imgur.com/wro3anq.png" width=70%>

# おわりに
Auth0がデフォルトで持っているUniversal LoginやLockライブラリを利用することでログインにまつわる工数を削減しながらセキュアなログインフローを実装できますが、ブランドイメージの毀損が懸念されるかと思います。Universal Loginをカスタマイズすることでログイン関連の工数削減・セキュリティの向上・ブランドイメージの保護を全て実現できます。