Select to view content in your preferred language

Implementing user authentication with Javascript API for Experience web app

37
1
5 hours ago
MalinEngelhardt
New Contributor

Hi,

I created an Experience with the ArcGIS Experience Builder Developer version, which is deployed on my server. Since I want users to use Analysis tools I have included in the Experience I need to implement user authentication. I want users to have a login button to then be able to view the map and use the tools in my experience.

I don't have much experience with authentication processes so I have not been able to include the authentication process properly into my Experience. So far I have come up with the following code:

 

<!doctype html>
<html lang="en-us">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no"/>
    <meta http-equiv="X-UA-Compatible" content="IE=EDGE"/>
    <meta name="google-site-verification" content="Gl928UcZRBt8t7njrpXivrsVrbVcc7sLybtCMZ6Dzlg"/>
    <title>Web GIS</title>
    <link rel="shortcut icon" href="assets/exb.ico">
    <link rel="stylesheet" href="https://js.arcgis.com/4.29/esri/themes/light/main.css">
	<base href="./cdn/4/"/>
	<script src="https://cdn.jsdelivr.net/npm/bowser@2.11.0/es5.js"></script>
    <style>
        * {
            scrollbar-color: var(--light-600) transparent;
        }
        html, body {
            width: 100%;
            height: 100%;
            margin: 0;
            overflow: hidden;
        }
        html.scrollable {
            overflow: auto;
        }
        html.scrollable body {
            overflow: unset;
        }
        html.scrollable body, html.scrollable #app {
            height: auto;
        }
        #loading {
            width: 100vw;
            height: 100vh;
        }
        #app {
            width: 100%;
            height: 100%;
            position: relative;
            z-index: 0;
            display: none;
        }
        .auth-buttons {
            position: absolute;
            top: 10px;
            right: 10px;
            z-index: 10;
        }
        .auth-buttons button {
            margin-left: 10px;
        }
    </style>
</head>

<body>
    <div id="loading">
        <style>
            .loading-content {
                position: absolute;
                top: 0;
                bottom: 0;
                left: 0;
                right: 0;
            }
            .jimu-primary-loading-app:before, .jimu-primary-loading-app:after {
                position: absolute;
                top: 0;
                content: '';
            }
            .jimu-primary-loading-app:before {
                left: -19.992px;
            }
            .jimu-primary-loading-app:after {
                left: 19.992px;
                -webkit-animation-delay: 0.32s !important;
                animation-delay: 0.32s !important;
            }
            .jimu-primary-loading-app:before, .jimu-primary-loading-app:after, .jimu-primary-loading-app {
                background: #076fe5;
                -webkit-animation: loading-keys-app-loading 0.8s infinite ease-in-out;
                animation: loading-keys-app-loading 0.8s infinite ease-in-out;
                width: 13.6px;
                height: 32px;
            }
            .jimu-primary-loading-app {
                text-indent: -9999em;
                margin: auto;
                position: absolute;
                right: calc(50% - 6.8px);
                top: calc(50% - 16px);
                -webkit-animation-delay: 0.16s !important;
                animation-delay: 0.16s !important;
            }
            @-webkit-keyframes loading-keys-app-loading {
                0%, 80%, 100% { opacity: .75; box-shadow: 0 0 #076fe5; height: 32px; }
                40% { opacity: 1; box-shadow: 0 -8px #076fe5; height: 40px; }
            }
            @keyframes loading-keys-app-loading {
                0%, 80%, 100% { opacity: .75; box-shadow: 0 0 #076fe5; height: 32px; }
                40% { opacity: 1; box-shadow: 0 -8px #076fe5; height: 40px; }
            }
        </style>
        <div class="loading-content">
            <div class="justify-content-center jimu-primary-loading-app"></div>
        </div>
    </div>

    <div id="app"></div>

    <div class="auth-buttons">
        <button id="sign-in" class="btn btn-primary">Sign In</button>
        <button id="sign-out" class="btn btn-primary" style="display:none;">Sign Out</button>
    </div>

    <pre><code id="results"></code></pre>

    <script type="webpack-options" id="webpack-options">{
        "mountPath": "/",
        "isOutOfExb": true,
        "hostEnv": "prod",
        "appFolderName": ".",
        "useStructuralUrl": false,
        "arcgisJsApiUrl": "https://js.arcgis.com/4.29/",
        "isDevEdition": true,
        "buildNumber": "1",
        "isBuilder": false,
        "isSite": false,
        "isInPortal": false
    }</script>

    <script type="systemjs-importmap">{
        "imports": {
            "jimu-core": "https://BASE_URL/jimu-core/index.js",
            "jimu-core/": "https://BASE_URL/jimu-core/",
            "jimu-theme": "https://BASE_URL/jimu-theme/index.js",
            "jimu-theme/": "https://BASE_URL/jimu-theme/",
            "jimu-ui": "https://BASE_URL/jimu-ui/index.js",
            "jimu-ui/": "https://BASE_URL/jimu-ui/",
            "jimu-icons/": "https://BASE_URL/jimu-icons/",
            "jimu-arcgis": "https://BASE_URL/jimu-arcgis/index.js",
            "jimu-arcgis/": "https://BASE_URL/jimu-arcgis/",
            "jimu-layouts": "https://BASE_URL/jimu-layouts/index.js",
            "jimu-layouts/": "https://BASE_URL/jimu-layouts/",
            "jimu-for-builder": "https://BASE_URL/jimu-for-builder/index.js",
            "jimu-for-builder/": "https://BASE_URL/jimu-for-builder/",
            "widgets/": "https://BASE_URL/widgets/",
            "themes/": "https://BASE_URL/themes/",
            "builder/": "https://BASE_URL/builder/",
            "site/": "https://BASE_URL/site/",
            "experience/": "https://BASE_URL/experience/",
            "template/": "https://BASE_URL/template/",
            "templates/": "https://BASE_URL/templates/",
            "calcite-components": "https://BASE_URL/calcite-components/index.js",
            "calcite-components/": "https://BASE_URL/calcite-components/",
            "arcgis-charts": "https://BASE_URL/arcgis-charts/arcgis-charts.js",
            "arcgis-amd-packages/": "https://amd-packages/",
            "esri/": "https://API_URL/esri/"
        }
    }</script>

    <script src="./jimu-core/init.js"></script>

    <!-- Authentication script -->
    <script>
        require([
            "esri/portal/Portal",
            "esri/identity/OAuthInfo",
            "esri/identity/IdentityManager"
        ], function (Portal, OAuthInfo, esriId) {

            const info = new OAuthInfo({
                appId: "My-APP-ID", // removed due to privacy reasons
                popup: false // Use false if you want to redirect instead of using a popup
            });
            esriId.registerOAuthInfos([info]);

            esriId.checkSignInStatus(info.portalUrl + "/sharing")
                .then(() => {
                    handleSignedIn();
                })
                .catch(() => {
                    handleSignedOut();
                });

            document.getElementById("sign-in").addEventListener("click", function () {
                esriId.getCredential(info.portalUrl + "/sharing");
            });

            document.getElementById("sign-out").addEventListener("click", function () {
                esriId.destroyCredentials();
                window.location.reload();
            });

            function handleSignedIn() {
                const portal = new Portal();
                portal.load().then(() => {
                    const results = {
                        name: portal.user.fullName,
                        username: portal.user.username
                    };
                    document.getElementById("results").innerText = JSON.stringify(results, null, 2);
                    document.getElementById("sign-in").style.display = "none";
                    document.getElementById("sign-out").style.display = "block";
                });
            }

            function handleSignedOut() {
                document.getElementById("results").innerText = 'Signed Out';
                document.getElementById("sign-in").style.display = "block";
                document.getElementById("sign-out").style.display = "none";
            }
        });
    </script>

</body>

</html>

 

This will load my Experience and display a button, but I can't log in due to a ReferenceError: require is not defined. Adding <script src="https://js.arcgis.com/4.29/"></script> in the header will result in a MultipleDefines Error instead.

Any help would be appreciated.

0 Kudos
1 Reply
CodyPatterson
Regular Contributor

Hey @MalinEngelhardt 

The MutipleDefines appears that it comes from the link that you're adding into the header, as require is defined many times.

Instead of require, you could use the System.import method to attempt and load the information in:

System.import('esri/portal/Portal').then(function (Portal) {
    System.import('esri/identity/OAuthInfo').then(function (OAuthInfo) {
        System.import('esri/identity/IdentityManager').then(function (esriId) {

If this doesn't end up working, you could attempt to import the functions at the top of your script, as in standard JS.

import <Portal> from <esri/portal/Portal>

And so on.

Hope that helps!

Cody

0 Kudos