Index: /trunk/src/org/openstreetmap/josm/gui/MainApplication.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 12802)
+++ /trunk/src/org/openstreetmap/josm/gui/MainApplication.java	(revision 12803)
@@ -107,4 +107,5 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.TMSLayer;
+import org.openstreetmap.josm.gui.oauth.OAuthAuthorizationWizard;
 import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
 import org.openstreetmap.josm.gui.preferences.display.LafPreference;
@@ -126,4 +127,5 @@
 import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.io.OsmApiInitializationException;
+import org.openstreetmap.josm.io.OsmConnection;
 import org.openstreetmap.josm.io.OsmTransferCanceledException;
 import org.openstreetmap.josm.io.OsmTransferException;
@@ -1070,4 +1072,5 @@
 
     static void setupCallbacks() {
+        OsmConnection.setOAuthAccessTokenFetcher(OAuthAuthorizationWizard::obtainAccessToken);
         MessageNotifier.setNotifierCallback(MainApplication::notifyNewMessages);
         DeleteCommand.setDeletionCallback(DeleteAction.defaultDeletionCallback);
Index: /trunk/src/org/openstreetmap/josm/gui/oauth/OAuthAuthorizationWizard.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/oauth/OAuthAuthorizationWizard.java	(revision 12802)
+++ /trunk/src/org/openstreetmap/josm/gui/oauth/OAuthAuthorizationWizard.java	(revision 12803)
@@ -21,5 +21,8 @@
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
 import java.util.concurrent.Executor;
+import java.util.concurrent.FutureTask;
 
 import javax.swing.AbstractAction;
@@ -30,4 +33,5 @@
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.event.HyperlinkEvent;
@@ -51,4 +55,5 @@
 import org.openstreetmap.josm.tools.OpenBrowser;
 import org.openstreetmap.josm.tools.UserCancelException;
+import org.openstreetmap.josm.tools.Utils;
 
 /**
@@ -333,4 +338,28 @@
     }
 
+    /**
+     * Obtains an OAuth access token for the connection. Afterwards, the token is accessible via {@link OAuthAccessTokenHolder}.
+     * @param serverUrl the URL to OSM server
+     * @throws InterruptedException if we're interrupted while waiting for the event dispatching thread to finish OAuth authorization task
+     * @throws InvocationTargetException if an exception is thrown while running OAuth authorization task
+     * @since 12803
+     */
+    public static void obtainAccessToken(final URL serverUrl) throws InvocationTargetException, InterruptedException {
+        final Runnable authTask = new FutureTask<>(() -> {
+            // Concerning Utils.newDirectExecutor: Main worker cannot be used since this connection is already
+            // executed via main worker. The OAuth connections would block otherwise.
+            final OAuthAuthorizationWizard wizard = new OAuthAuthorizationWizard(
+                    Main.parent, serverUrl.toExternalForm(), Utils.newDirectExecutor());
+            wizard.showDialog();
+            return wizard;
+        });
+        // exception handling differs from implementation at GuiHelper.runInEDTAndWait()
+        if (SwingUtilities.isEventDispatchThread()) {
+            authTask.run();
+        } else {
+            SwingUtilities.invokeAndWait(authTask);
+        }
+    }
+
     class AuthorisationProcedureChangeListener implements ItemListener {
         @Override
Index: /trunk/src/org/openstreetmap/josm/io/OsmConnection.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/OsmConnection.java	(revision 12802)
+++ /trunk/src/org/openstreetmap/josm/io/OsmConnection.java	(revision 12803)
@@ -11,18 +11,14 @@
 import java.util.Base64;
 import java.util.Objects;
-import java.util.concurrent.FutureTask;
-
-import javax.swing.SwingUtilities;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder;
 import org.openstreetmap.josm.data.oauth.OAuthParameters;
-import org.openstreetmap.josm.gui.oauth.OAuthAuthorizationWizard;
 import org.openstreetmap.josm.io.auth.CredentialsAgentException;
 import org.openstreetmap.josm.io.auth.CredentialsAgentResponse;
 import org.openstreetmap.josm.io.auth.CredentialsManager;
 import org.openstreetmap.josm.tools.HttpClient;
+import org.openstreetmap.josm.tools.JosmRuntimeException;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
 
 import oauth.signpost.OAuthConsumer;
@@ -39,4 +35,31 @@
     protected HttpClient activeConnection;
     protected OAuthParameters oauthParameters;
+
+    /**
+     * Retrieves OAuth access token.
+     * @since 12803
+     */
+    public interface OAuthAccessTokenFetcher {
+        /**
+         * Obtains an OAuth access token for the connection. Afterwards, the token is accessible via {@link OAuthAccessTokenHolder}.
+         * @param serverUrl the URL to OSM server
+         * @throws InterruptedException if we're interrupted while waiting for the event dispatching thread to finish OAuth authorization task
+         * @throws InvocationTargetException if an exception is thrown while running OAuth authorization task
+         */
+        void obtainAccessToken(URL serverUrl) throws InvocationTargetException, InterruptedException;
+    }
+
+    static OAuthAccessTokenFetcher fetcher = u -> {
+        throw new JosmRuntimeException("OsmConnection.setOAuthAccessTokenFetcher() has not been called");
+    };
+
+    /**
+     * Sets the OAuth access token fetcher.
+     * @param tokenFetcher new OAuth access token fetcher. Cannot be null
+     * @since 12803
+     */
+    public static void setOAuthAccessTokenFetcher(OAuthAccessTokenFetcher tokenFetcher) {
+        fetcher = Objects.requireNonNull(tokenFetcher, "tokenFetcher");
+    }
 
     /**
@@ -110,7 +133,8 @@
 
     /**
-     * Obtains an OAuth access token for the connection. Afterwards, the token is accessible via {@link OAuthAccessTokenHolder}.
+     * Obtains an OAuth access token for the connection.
+     * Afterwards, the token is accessible via {@link OAuthAccessTokenHolder} / {@link CredentialsManager}.
      * @param connection connection for which the access token should be obtained
-     * @throws MissingOAuthAccessTokenException if the process cannot be completec successfully
+     * @throws MissingOAuthAccessTokenException if the process cannot be completed successfully
      */
     protected void obtainAccessToken(final HttpClient connection) throws MissingOAuthAccessTokenException {
@@ -120,20 +144,7 @@
                 throw new MissingOAuthAccessTokenException();
             }
-            final Runnable authTask = new FutureTask<>(() -> {
-                // Concerning Utils.newDirectExecutor: Main worker cannot be used since this connection is already
-                // executed via main worker. The OAuth connections would block otherwise.
-                final OAuthAuthorizationWizard wizard = new OAuthAuthorizationWizard(
-                        Main.parent, apiUrl.toExternalForm(), Utils.newDirectExecutor());
-                wizard.showDialog();
-                OAuthAccessTokenHolder.getInstance().setSaveToPreferences(true);
-                OAuthAccessTokenHolder.getInstance().save(Main.pref, CredentialsManager.getInstance());
-                return wizard;
-            });
-            // exception handling differs from implementation at GuiHelper.runInEDTAndWait()
-            if (SwingUtilities.isEventDispatchThread()) {
-                authTask.run();
-            } else {
-                SwingUtilities.invokeAndWait(authTask);
-            }
+            fetcher.obtainAccessToken(apiUrl);
+            OAuthAccessTokenHolder.getInstance().setSaveToPreferences(true);
+            OAuthAccessTokenHolder.getInstance().save(Main.pref, CredentialsManager.getInstance());
         } catch (MalformedURLException | InterruptedException | InvocationTargetException e) {
             throw new MissingOAuthAccessTokenException(e);
Index: /trunk/src/org/openstreetmap/josm/tools/OsmUrlToBounds.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/OsmUrlToBounds.java	(revision 12802)
+++ /trunk/src/org/openstreetmap/josm/tools/OsmUrlToBounds.java	(revision 12803)
@@ -7,4 +7,5 @@
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.function.Supplier;
 
@@ -211,5 +212,5 @@
      */
     public static void setMapSizeSupplier(Supplier<Dimension> mapSizeSupplier) {
-        mapSize = mapSizeSupplier;
+        mapSize = Objects.requireNonNull(mapSizeSupplier, "mapSizeSupplier");
     }
 
