arcgis-authentication

SKILL.md

ArcGIS Authentication

Use this skill for implementing authentication, OAuth, API keys, and identity management.

OAuth 2.0 Authentication

Basic OAuth Setup

import OAuthInfo from "@arcgis/core/identity/OAuthInfo.js";
import esriId from "@arcgis/core/identity/IdentityManager.js";
import Portal from "@arcgis/core/portal/Portal.js";

// Create OAuthInfo with your app ID
const oauthInfo = new OAuthInfo({
  appId: "YOUR_APP_ID", // Register at developers.arcgis.com
  popup: false // false = redirect, true = popup window
});

// Register with IdentityManager
esriId.registerOAuthInfos([oauthInfo]);

Check Sign-In Status

async function checkSignIn() {
  try {
    await esriId.checkSignInStatus(oauthInfo.portalUrl + "/sharing");
    // User is signed in
    const portal = new Portal({ authMode: "immediate" });
    await portal.load();
    console.log("Signed in as:", portal.user.username);
    return portal;
  } catch {
    // User is not signed in
    console.log("Not signed in");
    return null;
  }
}

Sign In

async function signIn() {
  try {
    const credential = await esriId.getCredential(
      oauthInfo.portalUrl + "/sharing"
    );
    console.log("Credential obtained:", credential);
    return credential;
  } catch (error) {
    console.error("Sign in failed:", error);
  }
}

Sign Out

function signOut() {
  esriId.destroyCredentials();
  window.location.reload();
}

Complete OAuth Flow

import OAuthInfo from "@arcgis/core/identity/OAuthInfo.js";
import esriId from "@arcgis/core/identity/IdentityManager.js";
import Portal from "@arcgis/core/portal/Portal.js";

const oauthInfo = new OAuthInfo({
  appId: "YOUR_APP_ID"
});

esriId.registerOAuthInfos([oauthInfo]);

// Check if already signed in
esriId.checkSignInStatus(oauthInfo.portalUrl + "/sharing")
  .then(() => {
    // Already signed in, load portal
    const portal = new Portal({ authMode: "immediate" });
    return portal.load();
  })
  .then((portal) => {
    console.log("Welcome,", portal.user.fullName);
    displayUserContent(portal);
  })
  .catch(() => {
    // Not signed in, show sign-in button
    showSignInButton();
  });

function showSignInButton() {
  const btn = document.getElementById("signInBtn");
  btn.onclick = () => {
    esriId.getCredential(oauthInfo.portalUrl + "/sharing")
      .then(() => {
        window.location.reload();
      });
  };
}

OAuth Component

<!-- Using OAuth component -->
<arcgis-oauth app-id="YOUR_APP_ID"></arcgis-oauth>

<script type="module">
  const oauthComponent = document.querySelector("arcgis-oauth");

  oauthComponent.addEventListener("arcgisSignIn", (event) => {
    console.log("Signed in:", event.detail.credential);
  });

  oauthComponent.addEventListener("arcgisSignOut", () => {
    console.log("Signed out");
  });
</script>

API Keys

Configure API Key

import esriConfig from "@arcgis/core/config.js";

// Set API key for accessing services
esriConfig.apiKey = "YOUR_API_KEY";

// Now basemaps and services will use the API key
const map = new Map({
  basemap: "arcgis/streets" // Requires API key
});

API Key in HTML

<script>
  // Set before loading the SDK
  window.esriConfig = {
    apiKey: "YOUR_API_KEY"
  };
</script>
<script src="https://js.arcgis.com/4.34/"></script>

Enterprise Portal Authentication

Configure for Enterprise Portal

const oauthInfo = new OAuthInfo({
  appId: "YOUR_APP_ID",
  portalUrl: "https://your-portal.com/portal",
  popup: true
});

esriId.registerOAuthInfos([oauthInfo]);

Set Portal URL Globally

import esriConfig from "@arcgis/core/config.js";

esriConfig.portalUrl = "https://your-portal.com/portal";

Token-Based Authentication

Get Token Manually

const credential = await esriId.getCredential("https://services.arcgis.com/...");
console.log("Token:", credential.token);
console.log("Expires:", new Date(credential.expires));

Register Token

esriId.registerToken({
  server: "https://services.arcgis.com/",
  token: "YOUR_TOKEN"
});

Portal User Information

import Portal from "@arcgis/core/portal/Portal.js";

const portal = new Portal({ authMode: "immediate" });
await portal.load();

// User info
console.log("Username:", portal.user.username);
console.log("Full name:", portal.user.fullName);
console.log("Email:", portal.user.email);
console.log("Role:", portal.user.role);
console.log("Thumbnail:", portal.user.thumbnailUrl);

// Organization info
console.log("Org name:", portal.name);
console.log("Org ID:", portal.id);

Query User Items

import Portal from "@arcgis/core/portal/Portal.js";
import PortalQueryParams from "@arcgis/core/portal/PortalQueryParams.js";

const portal = new Portal({ authMode: "immediate" });
await portal.load();

// Query user's items
const queryParams = new PortalQueryParams({
  query: `owner:${portal.user.username}`,
  sortField: "modified",
  sortOrder: "desc",
  num: 20
});

const result = await portal.queryItems(queryParams);

result.results.forEach(item => {
  console.log(item.title, item.type, item.id);
});

Credential Persistence

// Clear stored credentials
esriId.destroyCredentials();

// Find a specific credential
const credential = esriId.findCredential("https://services.arcgis.com/...");

Handling Authentication Errors

// Global handler for authentication challenges
esriId.on("credential-create", (event) => {
  console.log("New credential created:", event.credential);
});

// Handle layer authentication errors
layer.on("layerview-create-error", (event) => {
  if (event.error.name === "identity-manager:not-authorized") {
    console.log("Authentication required for this layer");
    signIn();
  }
});

Trusted Servers

import esriConfig from "@arcgis/core/config.js";

// Add servers that should receive credentials automatically
esriConfig.request.trustedServers.push("https://services.arcgis.com");
esriConfig.request.trustedServers.push("https://your-server.com");

CORS and Proxy

import esriConfig from "@arcgis/core/config.js";

// Configure proxy for cross-origin requests
esriConfig.request.proxyUrl = "/proxy/";

// Configure proxy rules
esriConfig.request.proxyRules.push({
  urlPrefix: "https://services.arcgis.com",
  proxyUrl: "/proxy/"
});

Reference Samples

  • identity-oauth-basic - Basic OAuth2 authentication setup
  • identity-oauth-component - OAuth component-based authentication

Common Pitfalls

  1. App ID registration: App ID must be registered with correct redirect URIs

  2. Popup blockers: OAuth popup-based sign-in fails on mobile browsers.

    // Anti-pattern: using popup flow on mobile
    OAuthInfo.create({
      appId: "YOUR_APP_ID",
      popup: true // Blocked by most mobile browsers
    });
    
    // Correct: use redirect flow for mobile, popup for desktop
    const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent);
    OAuthInfo.create({
      appId: "YOUR_APP_ID",
      popup: !isMobile // Redirect flow on mobile, popup on desktop
    });
    

    Impact: On mobile browsers (Safari, Chrome for iOS/Android), the OAuth popup is silently blocked. The user sees no sign-in dialog and cannot authenticate, with no error message explaining why.

  3. Token expiration: Tokens expire - handle refresh or re-authentication

  4. CORS errors: Configure trusted servers or use proxy for cross-origin

  5. Portal URL trailing slash: A trailing slash in the portal URL causes token validation to fail.

    // Anti-pattern: portal URL with trailing slash
    const portal = new Portal({
      url: "https://myorg.maps.arcgis.com/" // Trailing slash
    });
    await portal.load(); // Token validation may fail
    
    // Correct: portal URL without trailing slash
    const portal = new Portal({
      url: "https://myorg.maps.arcgis.com" // No trailing slash
    });
    await portal.load();
    

    Impact: The portal URL with a trailing slash does not match the token's server URL during validation. Authentication silently fails, or the user is prompted to sign in repeatedly because the token is never accepted.

Weekly Installs
20
GitHub Stars
5
First Seen
Jan 22, 2026
Installed on
opencode18
gemini-cli17
codex17
github-copilot16
cursor16
claude-code15