From arcgis-maps-sdk-js-ai-context
Implement authentication with ArcGIS using OAuth 2.0, API keys, and identity management. Use for accessing secured services, portal items, and user-specific content.
How this skill is triggered — by the user, by Claude, or both
Slash command
/arcgis-maps-sdk-js-ai-context:arcgis-authenticationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use this skill for implementing authentication, OAuth, API keys, and identity management.
Use this skill for implementing authentication, OAuth, API keys, and identity management.
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]);
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;
}
}
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);
}
}
function signOut() {
esriId.destroyCredentials();
window.location.reload();
}
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();
});
};
}
Since there is no <arcgis-oauth> component in 4.26, implement sign-in/sign-out UI manually
using OAuthInfo + IdentityManager. This is the standard pattern for all 4.26 apps.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://js.arcgis.com/4.26/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.26/"></script>
<style>
html, body, #viewDiv { height: 100%; margin: 0; }
#userPanel { position: absolute; top: 10px; right: 10px; background: white; padding: 8px; z-index: 10; }
</style>
</head>
<body>
<div id="viewDiv"></div>
<div id="userPanel">
<span id="userName">Not signed in</span>
<button id="authBtn">Sign In</button>
</div>
<script>
require([
"esri/identity/OAuthInfo",
"esri/identity/IdentityManager",
"esri/portal/Portal",
"esri/Map",
"esri/views/MapView"
], (OAuthInfo, esriId, Portal, Map, MapView) => {
const info = new OAuthInfo({ appId: "YOUR_APP_ID" });
esriId.registerOAuthInfos([info]);
const view = new MapView({
container: "viewDiv",
map: new Map({ basemap: "topo-vector" })
});
const authBtn = document.getElementById("authBtn");
const userName = document.getElementById("userName");
// Check existing session
esriId.checkSignInStatus(info.portalUrl + "/sharing")
.then(onSignedIn)
.catch(() => {
authBtn.textContent = "Sign In";
authBtn.onclick = () => {
esriId.getCredential(info.portalUrl + "/sharing").then(onSignedIn);
};
});
function onSignedIn() {
const portal = new Portal({ authMode: "immediate" });
portal.load().then(() => {
userName.textContent = portal.user.fullName;
authBtn.textContent = "Sign Out";
authBtn.onclick = () => {
esriId.destroyCredentials();
window.location.reload();
};
});
}
});
</script>
</body>
</html>
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
});
<script>
// Set before loading the SDK
window.esriConfig = {
apiKey: "YOUR_API_KEY"
};
</script>
<script src="https://js.arcgis.com/4.26/"></script>
const oauthInfo = new OAuthInfo({
appId: "YOUR_APP_ID",
portalUrl: "https://your-portal.com/portal",
popup: true
});
esriId.registerOAuthInfos([oauthInfo]);
import esriConfig from "@arcgis/core/config.js";
esriConfig.portalUrl = "https://your-portal.com/portal";
const credential = await esriId.getCredential("https://services.arcgis.com/...");
console.log("Token:", credential.token);
console.log("Expires:", new Date(credential.expires));
esriId.registerToken({
server: "https://services.arcgis.com/",
token: "YOUR_TOKEN"
});
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);
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);
});
// Clear stored credentials
esriId.destroyCredentials();
// Find a specific credential
const credential = esriId.findCredential("https://services.arcgis.com/...");
// 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();
}
});
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");
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/"
});
identity-oauth-basic - Basic OAuth2 authentication setup with OAuthInfo and IdentityManageridentity-oauth-redirect - OAuth redirect flow with sign-in/sign-out UIidentity-api-key - API key configuration for public-facing appsApp ID registration: App ID must be registered with correct redirect URIs
Popup blockers: OAuth popup-based sign-in fails on mobile browsers.
// Anti-pattern: using popup flow on mobile
new OAuthInfo({
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);
new OAuthInfo({
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.
Token expiration: Tokens expire - handle refresh or re-authentication
CORS errors: Configure trusted servers or use proxy for cross-origin
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.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub elowen53/arcgis-maps-sdk-js-ai-context-4.0 --plugin arcgis-maps-sdk-js-ai-context