Index: trunk/src/org/openstreetmap/josm/gui/MainInitialization.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainInitialization.java	(revision 15854)
+++ trunk/src/org/openstreetmap/josm/gui/MainInitialization.java	(revision 15855)
@@ -30,4 +30,5 @@
 import org.openstreetmap.josm.io.OsmApiInitializationException;
 import org.openstreetmap.josm.io.OsmTransferCanceledException;
+import org.openstreetmap.josm.io.imagery.ApiKeyProvider;
 import org.openstreetmap.josm.spi.lifecycle.InitializationSequence;
 import org.openstreetmap.josm.spi.lifecycle.InitializationTask;
@@ -143,4 +144,5 @@
             new InitializationTask(tr("Updating user interface"), () -> GuiHelper.runInEDTAndWait(() -> {
                 // hooks for the jmapviewer component
+                FeatureAdapter.registerApiKeyAdapter(ApiKeyProvider::retrieveApiKey);
                 FeatureAdapter.registerBrowserAdapter(OpenBrowser::displayUrl);
                 FeatureAdapter.registerImageAdapter(ImageProvider::read);
Index: trunk/src/org/openstreetmap/josm/io/imagery/ApiKeyProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/imagery/ApiKeyProvider.java	(revision 15855)
+++ trunk/src/org/openstreetmap/josm/io/imagery/ApiKeyProvider.java	(revision 15855)
@@ -0,0 +1,50 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io.imagery;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+
+import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.tools.HttpClient;
+import org.openstreetmap.josm.tools.HttpClient.Response;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * Provider of confidential imagery API keys.
+ * @since 15855
+ */
+public final class ApiKeyProvider {
+
+    private ApiKeyProvider() {
+        // Hide public constructor
+    }
+
+    private static List<String> getApiKeySites() {
+        return Preferences.main().getList("apikey.sites",
+                Collections.singletonList(Config.getUrls().getJOSMWebsite()+"/mapkey/"));
+    }
+
+    /**
+     * Retrieves the API key for the given imagery id.
+     * @param imageryId imagery id
+     * @return the API key for the given imagery id
+     * @throws IOException in case of I/O error
+     */
+    public static String retrieveApiKey(String imageryId) throws IOException {
+        for (String siteUrl : getApiKeySites()) {
+            Response response = HttpClient.create(new URL(siteUrl + imageryId)).connect();
+            try {
+                if (response.getResponseCode() == HttpURLConnection.HTTP_OK) {
+                    return Utils.strip(response.fetchContent());
+                }
+            } finally {
+                response.disconnect();
+            }
+        }
+        return null;
+    }
+}
