Index: trunk/src/org/openstreetmap/josm/data/imagery/ImageryPatterns.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/imagery/ImageryPatterns.java	(revision 18368)
+++ trunk/src/org/openstreetmap/josm/data/imagery/ImageryPatterns.java	(revision 18371)
@@ -5,4 +5,5 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.Map;
@@ -10,4 +11,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+
+import org.openstreetmap.gui.jmapviewer.FeatureAdapter;
 
 /**
@@ -30,4 +33,9 @@
     static final Pattern PATTERN_TIME   = Pattern.compile("\\{time\\}"); // Sentinel-2
     static final Pattern PATTERN_PARAM  = Pattern.compile("\\{([^}]+)\\}");
+    /**
+     * The api key pattern is used to allow us to quickly switch apikeys. This is functionally the same as the pattern
+     * in {@link org.openstreetmap.gui.jmapviewer.tilesources.TemplatedTMSTileSource}.
+     */
+    static final Pattern PATTERN_API_KEY = Pattern.compile("\\{apikey}");
     // CHECKSTYLE.ON: SingleSpaceSeparator
 
@@ -35,9 +43,10 @@
             PATTERN_HEADER, PATTERN_PROJ, PATTERN_WKID, PATTERN_BBOX,
             PATTERN_W, PATTERN_S, PATTERN_E, PATTERN_N,
-            PATTERN_WIDTH, PATTERN_HEIGHT, PATTERN_TIME
+            PATTERN_WIDTH, PATTERN_HEIGHT, PATTERN_TIME,
+            PATTERN_API_KEY
     };
 
     private static final Pattern[] ALL_WMTS_PATTERNS = {
-            PATTERN_HEADER
+            PATTERN_HEADER, PATTERN_API_KEY
     };
 
@@ -75,3 +84,22 @@
         return output.toString();
     }
+
+    /**
+     * Handle the {@link #PATTERN_API_KEY} replacement
+     * @param id The id of the info
+     * @param url The templated url
+     * @return The templated url with {@link #PATTERN_API_KEY} replaced
+     */
+    static String handleApiKeyTemplate(final String id, final String url) {
+        if (id != null && url != null) {
+            try {
+                final String apiKey = FeatureAdapter.retrieveApiKey(id);
+                return PATTERN_API_KEY.matcher(url).replaceAll(apiKey);
+            } catch (IOException | NullPointerException e) {
+                // Match rough behavior in JMapViewer TemplatedTMSTileSource, but with better error message.
+                throw new IllegalArgumentException(tr("Could not retrieve API key for imagery with id={0}. Cannot add layer.", id), e);
+            }
+        }
+        return url;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/imagery/TemplatedWMSTileSource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/imagery/TemplatedWMSTileSource.java	(revision 18368)
+++ trunk/src/org/openstreetmap/josm/data/imagery/TemplatedWMSTileSource.java	(revision 18371)
@@ -45,5 +45,5 @@
         this.headers.putAll(info.getCustomHttpHeaders());
         this.date = info.getDate();
-        this.baseUrl = ImageryPatterns.handleHeaderTemplate(baseUrl, headers);
+        this.baseUrl = ImageryPatterns.handleApiKeyTemplate(info.getId(), ImageryPatterns.handleHeaderTemplate(baseUrl, headers));
         initProjection();
         // Bounding box coordinates have to be switched for WMS 1.3.0 EPSG:4326.
Index: trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java	(revision 18368)
+++ trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java	(revision 18371)
@@ -361,5 +361,6 @@
         CheckParameterUtil.ensureThat(info.getDefaultLayers().size() < 2, "At most 1 default layer for WMTS is supported");
         this.headers.putAll(info.getCustomHttpHeaders());
-        this.baseUrl = GetCapabilitiesParseHelper.normalizeCapabilitiesUrl(ImageryPatterns.handleHeaderTemplate(info.getUrl(), headers));
+        this.baseUrl = GetCapabilitiesParseHelper.normalizeCapabilitiesUrl(
+                ImageryPatterns.handleApiKeyTemplate(info.getId(), ImageryPatterns.handleHeaderTemplate(info.getUrl(), headers)));
         WMTSCapabilities capabilities = getCapabilities(baseUrl, headers);
         this.layers = capabilities.getLayers();
