Index: src/org/openstreetmap/josm/data/UserIdentityManager.java
===================================================================
--- src/org/openstreetmap/josm/data/UserIdentityManager.java	(revision 14995)
+++ src/org/openstreetmap/josm/data/UserIdentityManager.java	(working copy)
@@ -4,6 +4,11 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder;
 import org.openstreetmap.josm.data.osm.User;
@@ -14,6 +19,7 @@
 import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.io.OsmServerUserInfoReader;
 import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.io.auth.CredentialsAgentResponse;
 import org.openstreetmap.josm.io.auth.CredentialsManager;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.spi.preferences.PreferenceChangeEvent;
@@ -78,16 +84,20 @@
                 instance.initFromPreferences();
             }
             Config.getPref().addPreferenceChangeListener(instance);
+            instance.populateAllUsers();
         }
         return instance;
     }
 
-    private String userName;
-    private UserInfo userInfo;
     private boolean accessTokenKeyChanged;
     private boolean accessTokenSecretChanged;
 
+    private String userName;
+    private UserInfo userInfo;
+    private LinkedHashMap<String, UserInfo> users;
+
     private UserIdentityManager() {
+        users = new LinkedHashMap<>();
     }
 
     /**
@@ -112,7 +122,7 @@
         if (trimmedUserName.isEmpty())
             throw new IllegalArgumentException(
                     MessageFormat.format("Expected non-empty value for parameter ''{0}'', got ''{1}''", "userName", userName));
-        this.userName = trimmedUserName;
+        userName = trimmedUserName;
         userInfo = null;
     }
 
@@ -132,7 +142,7 @@
         if (trimmedUserName.isEmpty())
             throw new IllegalArgumentException(tr("Expected non-empty value for parameter ''{0}'', got ''{1}''", "userName", userName));
         CheckParameterUtil.ensureParameterNotNull(userInfo, "userInfo");
-        this.userName = trimmedUserName;
+        userName = trimmedUserName;
         this.userInfo = userInfo;
     }
 
@@ -238,6 +248,96 @@
     }
 
     /**
+     * Initializes the user identity manager from OAuth request of user details.
+     * @param oauth The {@code OAuthAccessTokenHolder} with the key and secret
+     * @see #initFromPreferences
+     * @since xxx
+     */
+    public void initFromOauth(OAuthAccessTokenHolder oauth) {
+        try {
+            OsmServerUserInfoReader osmServerReader = new OsmServerUserInfoReader();
+            UserInfo info = osmServerReader.fetchUserInfo(NullProgressMonitor.INSTANCE, oauth);
+            setFullyIdentified(info.getDisplayName(), info);
+        } catch (IllegalArgumentException | OsmTransferException e) {
+            Logging.error(e);
+        }
+    }
+
+    private List<Map<String, String>> getDefaultOAuthList() {
+        Map<String, String> variables = new TreeMap<>();
+        TreeMap<String, String> vars = new TreeMap<>();
+        vars.put("url", "osm-server.url");
+        vars.put("login", "oauth.access-token.key");
+        vars.put("password", "oauth.access-token.secret");
+        vars.put("login-token-url", "oauth.settings.authorise-token-url");
+        vars.put("auth-url", "oauth.settings.authorise-url");
+        vars.put("consumer-key", "oauth.settings.consumer-key");
+        vars.put("consumer-secret", "oauth.settings.consumer-secret");
+        vars.put("login-url", "oauth.settings.osm-login-url");
+        vars.put("logout-url", "oauth.settings.osm-logout-url");
+        variables.put("auth-type", "oauth");
+
+        vars.forEach((key, value) -> variables.put(key, Config.getPref().get(value)));
+        List<Map<String, String>> rList = new ArrayList<>();
+        rList.add(variables);
+        return rList;
+    }
+
+    private List<Map<String, String>> getDefaultBasicAuthList() {
+        Map<String, String> variables = new TreeMap<>();
+        TreeMap<String, String> vars = new TreeMap<>();
+
+        vars.put("url", "osm-server-url");
+        vars.put("login", "osm-server.username");
+        vars.put("password", "osm-server.password");
+
+        variables.put("auth-type", "basic");
+        vars.forEach((key, value) -> variables.put(key, Config.getPref().get(value)));
+        List<Map<String, String>> rList = new ArrayList<>();
+        return rList;
+    }
+
+    private List<Map<String, String>> getDefaultAuthList() {
+        List<Map<String, String>> rMap = getDefaultOAuthList();
+        rMap.addAll(getDefaultBasicAuthList());
+        return rMap;
+    }
+
+    /**
+     * Populate the users
+     * @since xxx
+     */
+    public void populateAllUsers() {
+        List<Map<String, String>> authList = Config.getPref().getListOfMaps("all-authorizations", getDefaultAuthList());
+        for (Map<String, String> map : authList) { // TODO fix
+            if ("oauth".equals(map.get("auth-type"))) {
+                OAuthAccessTokenHolder oauth = new OAuthAccessTokenHolder();
+                oauth.setAccessToken(map.get("login"), map.get("password"));
+                oauth.setOsmApi(map.get("url"));
+                instance.initFromOauth(oauth);
+                users.put(getUserName(), getUserInfo());
+            } else if ("basic".equals(map.get("auth-type"))) {
+                CredentialsAgentResponse response = new CredentialsAgentResponse();
+                response.setUsername(map.get("login"));
+                response.setPassword(map.get("password").toCharArray());
+            }
+        }
+
+        if (OsmApi.isUsingOAuth() && OAuthAccessTokenHolder.getInstance().containsAccessToken() &&
+                !NetworkManager.isOffline(OnlineResource.OSM_API)) {
+            try {
+                instance.initFromOAuth();
+            } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) {
+                Logging.error(e);
+                // Fall back to preferences if OAuth identification fails for any reason
+                instance.initFromPreferences();
+            }
+        } else {
+            instance.initFromPreferences();
+        }
+    }
+
+    /**
      * Replies true if the user with name <code>username</code> is the current user
      *
      * @param userName the user name
@@ -264,6 +364,42 @@
         }
     }
 
+    /**
+     * Get all information on all users that have logged in to JOSM
+     * @return A {@code HashMap} with username/UserInfo pairs.
+     * @since xxx
+     */
+    public Map<String, UserInfo> getAllUserInformation() {
+        if (users == null) {
+            populateAllUsers();
+        }
+        return users;
+    }
+
+    /**
+     * Get user authentication information
+     * @return The user information (passwords are protected)
+     * @since xxx
+     */
+    public List<Map<String, String>> getUserAuthInformation() {
+        List<Map<String, String>> authList = Config.getPref().getListOfMaps("all-authorizations", getDefaultAuthList());
+        for (Map<String, String> map : authList) {
+            if ("basic".equals(map.get("auth-type"))) {
+                // TODO protect passwords, even though they are stored in plain text
+                // map.put("password", "PROTECTED");
+            }
+        }
+        return authList;
+    }
+
+    /**
+     * Save authentication information
+     * @param users To save (any user NOT in this map WILL be deleted)
+     */
+    public void saveUserAuthInformation(List<Map<String, String>> users) {
+        Config.getPref().putListOfMaps("all-authorizations", users);
+    }
+
     /* ------------------------------------------------------------------- */
     /* interface PreferenceChangeListener                                  */
     /* ------------------------------------------------------------------- */
Index: src/org/openstreetmap/josm/data/oauth/OAuthAccessTokenHolder.java
===================================================================
--- src/org/openstreetmap/josm/data/oauth/OAuthAccessTokenHolder.java	(revision 14995)
+++ src/org/openstreetmap/josm/data/oauth/OAuthAccessTokenHolder.java	(working copy)
@@ -3,6 +3,12 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.openstreetmap.josm.data.UserIdentityManager;
+import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.io.auth.CredentialsAgent;
 import org.openstreetmap.josm.io.auth.CredentialsAgentException;
 import org.openstreetmap.josm.spi.preferences.Config;
@@ -16,6 +22,8 @@
 public class OAuthAccessTokenHolder {
     private static OAuthAccessTokenHolder instance;
 
+    private OsmApi osmApi = OsmApi.getOsmApi();
+
     /**
      * Replies the unique instance.
      * @return The unique instance of {@code OAuthAccessTokenHolder}
@@ -183,9 +191,42 @@
             Logging.warn(tr("Failed to store OAuth Access Token to credentials manager"));
             Logging.warn(tr("Current credential manager is of type ''{0}''", cm.getClass().getName()));
         }
+        List<Map<String, String>> users = UserIdentityManager.getInstance().getUserAuthInformation();
+        boolean present = false;
+        for (Map<String, String> user : users) {
+            if ("oauth".equals(user.get("auth-type")) && accessTokenKey.equals(user.get("auth-type"))) {
+                user.put("password", accessTokenSecret);
+                user.put("url", osmApi.getHost());
+                present = true;
+                break;
+            }
+        }
+        if (!present) {
+            Map<String, String> map = new TreeMap<>();
+            map.put("login", accessTokenKey);
+            map.put("password", accessTokenSecret);
+            map.put("url", osmApi.getHost());
+        }
     }
 
     /**
+     * Set the API to use with the user
+     * @param serverUrl The URL for the OSM server
+     * @since xxx
+     */
+    public void setOsmApi(String serverUrl) {
+        osmApi = OsmApi.getOsmApi(serverUrl);
+    }
+
+    /**
+     * Get the osmApi for use with this oauth object
+     * @return The OsmApi to use
+     */
+    public OsmApi getOsmApi() {
+        return osmApi;
+    }
+
+    /**
      * Clears the content of this holder
      */
     public void clear() {
Index: src/org/openstreetmap/josm/gui/io/UploadParameterSummaryPanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/io/UploadParameterSummaryPanel.java	(revision 14995)
+++ src/org/openstreetmap/josm/gui/io/UploadParameterSummaryPanel.java	(working copy)
@@ -5,17 +5,24 @@
 import static org.openstreetmap.josm.tools.I18n.trn;
 
 import java.awt.BorderLayout;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.util.Map;
 import java.util.Optional;
 
 import javax.swing.BorderFactory;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.event.HyperlinkEvent;
 import javax.swing.event.HyperlinkListener;
 
+import org.openstreetmap.josm.data.UserIdentityManager;
 import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.UserInfo;
 import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
 import org.openstreetmap.josm.io.Capabilities;
 import org.openstreetmap.josm.io.OsmApi;
@@ -22,6 +29,7 @@
 import org.openstreetmap.josm.io.UploadStrategySpecification;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Logging;
 
 /**
  * A panel that displays a summary of data the user is about to upload
@@ -114,6 +122,27 @@
         return msg;
     }
 
+    protected JComboBox<String> buildPossibleUserBox() {
+        DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
+        Map<String, UserInfo> info = UserIdentityManager.getInstance().getAllUserInformation();
+        info.forEach((userName, userInfo) -> model.addElement(userName));
+        JComboBox<String> rBox = new JComboBox<>(model);
+        UserInfo user = UserIdentityManager.getInstance().getUserInfo();
+        String userName = user.getDisplayName() != null ? user.getDisplayName() : tr("Please login");
+        if (model.getIndexOf(userName) < 0) model.addElement(userName);
+        model.setSelectedItem(userName);
+        rBox.addItemListener(new ItemListener() {
+            @Override
+            public void itemStateChanged(ItemEvent e) {
+                if (e.getStateChange() == ItemEvent.SELECTED) {
+                    Logging.info("{0} was selected, switching to {1}", userName, e.getItem());
+                    model.setSelectedItem(e.getItem());
+                }
+            }
+        });
+        return rBox;
+    }
+
     protected void build() {
         jepMessage = new JMultilineLabel("");
         jepMessage.addHyperlinkListener(this);
@@ -128,6 +157,8 @@
         JPanel pnl = new JPanel(new BorderLayout());
         pnl.add(lblWarning, BorderLayout.NORTH);
         add(pnl, BorderLayout.WEST);
+        JComboBox<String> options = buildPossibleUserBox();
+        if (options.getItemCount() > 1) add(buildPossibleUserBox(), BorderLayout.SOUTH);
     }
 
     public void setConfigurationParameterRequestListener(ConfigurationParameterRequestHandler handler) {
Index: src/org/openstreetmap/josm/gui/preferences/server/AuthenticationPreferencesPanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/server/AuthenticationPreferencesPanel.java	(revision 14995)
+++ src/org/openstreetmap/josm/gui/preferences/server/AuthenticationPreferencesPanel.java	(working copy)
@@ -3,26 +3,27 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.BorderLayout;
-import java.awt.GridBagConstraints;
+import java.awt.Component;
+import java.awt.Dimension;
 import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
+import java.awt.event.ActionEvent;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 
-import javax.swing.ButtonGroup;
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
 import javax.swing.JPanel;
-import javax.swing.JRadioButton;
 import javax.swing.JSeparator;
 
-import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder;
+import org.openstreetmap.josm.data.UserIdentityManager;
 import org.openstreetmap.josm.gui.help.HelpUtil;
 import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
 import org.openstreetmap.josm.io.OsmApi;
-import org.openstreetmap.josm.io.auth.CredentialsManager;
 import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.Logging;
 
 /**
@@ -31,19 +32,26 @@
  */
 public class AuthenticationPreferencesPanel extends VerticallyScrollablePanel implements PropertyChangeListener {
 
-    /** indicates whether we use basic authentication */
-    private final JRadioButton rbBasicAuthentication = new JRadioButton();
-    /** indicates whether we use OAuth as authentication scheme */
-    private final JRadioButton rbOAuth = new JRadioButton();
+    /** add a basic authentication method */
+    private final JButton rbBasicAuthentication = new JButton(tr("Add Basic Authentication"));
+    /** add a OAuth method */
+    private final JButton rbOAuth = new JButton(tr("Add OAuth"));
     /** the panel which contains the authentication parameters for the respective authentication scheme */
-    private final JPanel pnlAuthenticationParameteters = new JPanel(new BorderLayout());
-    /** the panel for the basic authentication parameters */
-    private BasicAuthenticationPreferencesPanel pnlBasicAuthPreferences;
-    /** the panel for the OAuth authentication parameters */
-    private OAuthAuthenticationPreferencesPanel pnlOAuthPreferences;
+    private final JPanel pnlAuthenticationParameteters = new JPanel();
+    /** the panels for the basic authentication parameters */
+    private List<BasicAuthenticationPreferencesPanel> pnlBasicAuthPreferences;
+    /** the panels for the OAuth authentication parameters */
+    private List<OAuthAuthenticationPreferencesPanel> pnlOAuthPreferences;
     /** the panel for messages notifier preferences */
     private FeaturesPanel pnlFeaturesPreferences;
 
+    /** The authentication preference key */
+    public static final String AUTH_TYPE_KEY = "auth-type";
+    /** The value in {@code AUTH_TYPE_KEY}'s pref for OAuth */
+    public static final String AUTH_OAUTH = "oauth";
+    /** The value in {@code AUTH_TYPE_KEY}'s pref for basic authentication */
+    public static final String AUTH_BASIC = "basic";
+
     /**
      * Constructs a new {@code AuthenticationPreferencesPanel}.
      */
@@ -58,68 +66,149 @@
      */
     protected final void build() {
         setLayout(new GridBagLayout());
-        GridBagConstraints gc = new GridBagConstraints();
 
-        AuthenticationMethodChangeListener authChangeListener = new AuthenticationMethodChangeListener();
+        //-- the panel for API feature preferences
+        pnlFeaturesPreferences = new FeaturesPanel();
+        add(pnlFeaturesPreferences, GBC.eol());
 
         // -- radio button for basic authentication
-        gc.anchor = GridBagConstraints.NORTHWEST;
-        gc.fill = GridBagConstraints.HORIZONTAL;
-        gc.gridx = 1;
-        gc.weightx = 1.0;
-        gc.insets = new Insets(0, 0, 0, 3);
-        add(rbBasicAuthentication, gc);
-        rbBasicAuthentication.setText(tr("Use Basic Authentication"));
-        rbBasicAuthentication.setToolTipText(tr("Select to use HTTP basic authentication with your OSM username and password"));
-        rbBasicAuthentication.addItemListener(authChangeListener);
+        rbBasicAuthentication.setAction(new AbstractAction() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                BasicAuthenticationPreferencesPanel panel = new BasicAuthenticationPreferencesPanel();
+                panel.initFromPreferences();
+                if (isPresent(panel)) {
+                    panel.setUserName("");
+                }
+                if (!isPresent(panel)) {
+                    redrawAuthenticationPanel(panel);
+                }
+            }
+        });
+        rbBasicAuthentication.setText(tr("Add Basic Authentication"));
+        rbBasicAuthentication.setToolTipText(tr("Select to add HTTP basic authentication with your OSM username and password"));
 
         //-- radio button for OAuth
-        gc.gridx = 0;
-        gc.weightx = 0.0;
-        add(rbOAuth, gc);
-        rbOAuth.setText(tr("Use OAuth"));
-        rbOAuth.setToolTipText(tr("Select to use OAuth as authentication mechanism"));
-        rbOAuth.addItemListener(authChangeListener);
+        rbOAuth.setAction(new AbstractAction() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                OAuthAuthenticationPreferencesPanel panel = new OAuthAuthenticationPreferencesPanel();
+                panel.initFromPreferences();
+                redrawAuthenticationPanel(panel);
+            }
+        });
+        rbOAuth.setText(tr("Add OAuth"));
+        rbOAuth.setToolTipText(tr("Select to add a OAuth authentication mechanism"));
 
-        //-- radio button for OAuth
-        ButtonGroup bg = new ButtonGroup();
-        bg.add(rbBasicAuthentication);
-        bg.add(rbOAuth);
+        add(new JSeparator(), GBC.eol());
 
         //-- add the panel which will hold the authentication parameters
-        gc.gridx = 0;
-        gc.gridy = 1;
-        gc.gridwidth = 2;
-        gc.fill = GridBagConstraints.BOTH;
-        gc.weightx = 1.0;
-        gc.weighty = 1.0;
-        add(pnlAuthenticationParameteters, gc);
 
+        add(pnlAuthenticationParameteters, GBC.eol());
+        add(rbBasicAuthentication);
+        add(rbOAuth, GBC.eol());
+
         //-- the two panels for authentication parameters
-        pnlBasicAuthPreferences = new BasicAuthenticationPreferencesPanel();
-        pnlOAuthPreferences = new OAuthAuthenticationPreferencesPanel();
+        pnlBasicAuthPreferences = new ArrayList<>();
+        pnlOAuthPreferences = new ArrayList<>();
 
-        rbBasicAuthentication.setSelected(true);
-        pnlAuthenticationParameteters.add(pnlBasicAuthPreferences, BorderLayout.CENTER);
+        populateAuthPanels();
+    }
 
-        gc.gridy = 2;
-        add(new JSeparator(), gc);
+    private void populateAuthPanels() {
+        List<Map<String, String>> users = UserIdentityManager.getInstance().getUserAuthInformation();
+        for (Map<String, String> user : users) {
+            if (AUTH_OAUTH.equals(user.get(AUTH_TYPE_KEY))) {
+                OAuthAuthenticationPreferencesPanel panel = new OAuthAuthenticationPreferencesPanel();
+                panel.initFromMap(user);
+                redrawAuthenticationPanel(panel);
+            } else if (AUTH_BASIC.equals(user.get(AUTH_TYPE_KEY))) {
+                BasicAuthenticationPreferencesPanel panel = new BasicAuthenticationPreferencesPanel();
+                panel.initFromMap(user);
+                redrawAuthenticationPanel(panel);
+            } else if (user.get(AUTH_TYPE_KEY) != null) {
+                Logging.info("Unknown authentication type: {0}", user.get(AUTH_TYPE_KEY));
+            } else {
+                Logging.error("There was no authentication type");
+            }
+        }
+    }
 
-        //-- the panel for API feature preferences
-        gc.gridy = 3;
-        gc.fill = GridBagConstraints.NONE;
-        pnlFeaturesPreferences = new FeaturesPanel();
-        add(pnlFeaturesPreferences, gc);
+    private void redrawAuthenticationPanel(JPanel panel) {
+        if (panel == null) {
+            recalculateAuthenticationParametersSize();
+            pnlAuthenticationParameteters.revalidate();
+            return;
+        }
+        List<Component> components = new ArrayList<>();
+        JButton remove = new JButton(tr("Remove"));
+        components.add(panel);
+        components.add(new JSeparator());
+        remove.setAction(new AbstractAction() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                for (Component component : components) {
+                    if (pnlOAuthPreferences.contains(component)) {
+                        pnlOAuthPreferences.remove(component);
+                    }
+                    if (pnlBasicAuthPreferences.contains(component)) {
+                        pnlBasicAuthPreferences.remove(component);
+                    }
+                    pnlAuthenticationParameteters.remove(component);
+                    redrawAuthenticationPanel(null);
+                }
+            }
+        });
+        remove.setText(tr("Remove"));
+        components.add(remove);
+        for (Component component : components) {
+            pnlAuthenticationParameteters.add(component, GBC.eol());
+        }
+        if (panel instanceof BasicAuthenticationPreferencesPanel) {
+            pnlBasicAuthPreferences.add((BasicAuthenticationPreferencesPanel) panel);
+        } else if (panel instanceof OAuthAuthenticationPreferencesPanel) {
+            pnlOAuthPreferences.add((OAuthAuthenticationPreferencesPanel) panel);
+        }
+        recalculateAuthenticationParametersSize();
+        pnlAuthenticationParameteters.revalidate();
     }
 
+    private void recalculateAuthenticationParametersSize() {
+        Dimension d = new Dimension();
+        for (Component component : pnlAuthenticationParameteters.getComponents()) {
+            Dimension dComponent = component.getPreferredSize();
+            d.setSize(Math.max(d.getWidth(), dComponent.getWidth()), d.getHeight() + dComponent.getHeight());
+        }
+        pnlAuthenticationParameteters.setPreferredSize(d);
+    }
+
+    private boolean isPresent(Component component) {
+        List<Component> components = new ArrayList<>();
+        for (Component tcomponent : pnlAuthenticationParameteters.getComponents()) {
+            components.add(tcomponent);
+        }
+        if (component instanceof BasicAuthenticationPreferencesPanel) {
+            BasicAuthenticationPreferencesPanel realComponent = (BasicAuthenticationPreferencesPanel) component;
+            for (BasicAuthenticationPreferencesPanel check : pnlBasicAuthPreferences) {
+                if (check.equals(realComponent)) return true;
+            }
+        } else if (component instanceof OAuthAuthenticationPreferencesPanel) {
+            OAuthAuthenticationPreferencesPanel realComponent = (OAuthAuthenticationPreferencesPanel) component;
+            for (OAuthAuthenticationPreferencesPanel check : pnlOAuthPreferences) {
+                if (check.equals(realComponent)) return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Initializes the panel from preferences
      */
     public final void initFromPreferences() {
         final String authMethod = OsmApi.getAuthMethod();
-        if ("basic".equals(authMethod)) {
+        if (AUTH_BASIC.equals(authMethod)) {
             rbBasicAuthentication.setSelected(true);
-        } else if ("oauth".equals(authMethod)) {
+        } else if (AUTH_OAUTH.equals(authMethod)) {
             rbOAuth.setSelected(true);
         } else {
             Logging.warn(tr("Unsupported value in preference ''{0}'', got ''{1}''. Using authentication method ''Basic Authentication''.",
@@ -126,8 +215,18 @@
                     "osm-server.auth-method", authMethod));
             rbBasicAuthentication.setSelected(true);
         }
-        pnlBasicAuthPreferences.initFromPreferences();
-        pnlOAuthPreferences.initFromPreferences();
+        List<Map<String, String>> users = UserIdentityManager.getInstance().getUserAuthInformation();
+        for (Map<String, String> user : users) {
+            if (AUTH_OAUTH.equals(user.get(AUTH_TYPE_KEY))) {
+                OAuthAuthenticationPreferencesPanel panel = new OAuthAuthenticationPreferencesPanel();
+                panel.initFromMap(user);
+                pnlOAuthPreferences.add(panel);
+            } else if (AUTH_BASIC.equals(user.get(AUTH_TYPE_KEY))) {
+                BasicAuthenticationPreferencesPanel panel = new BasicAuthenticationPreferencesPanel();
+                panel.initFromMap(user);
+                pnlBasicAuthPreferences.add(panel);
+            }
+        }
         pnlFeaturesPreferences.initFromPreferences();
     }
 
@@ -137,50 +236,29 @@
     public final void saveToPreferences() {
         // save the authentication method
         String authMethod;
-        if (rbBasicAuthentication.isSelected()) {
-            authMethod = "basic";
+        if (pnlOAuthPreferences.isEmpty()) {
+            authMethod = AUTH_OAUTH;
         } else {
-            authMethod = "oauth";
+            authMethod = AUTH_BASIC;
         }
         Config.getPref().put("osm-server.auth-method", authMethod);
-        if ("basic".equals(authMethod)) {
-            // save username and password and clear the OAuth token
-            pnlBasicAuthPreferences.saveToPreferences();
-            OAuthAccessTokenHolder.getInstance().clear();
-            OAuthAccessTokenHolder.getInstance().save(CredentialsManager.getInstance());
-        } else if ("oauth".equals(authMethod)) {
-            // clear the password in the preferences
-            pnlBasicAuthPreferences.clearPassword();
-            pnlBasicAuthPreferences.saveToPreferences();
-            pnlOAuthPreferences.saveToPreferences();
+        for (BasicAuthenticationPreferencesPanel panel : pnlBasicAuthPreferences) {
+            panel.saveToPreferences();
         }
+        for (OAuthAuthenticationPreferencesPanel panel : pnlOAuthPreferences) {
+            panel.saveToPreferences();
+        }
         // save message notifications preferences. To be done after authentication preferences.
         pnlFeaturesPreferences.saveToPreferences();
     }
 
-    /**
-     * Listens to changes in the authentication method
-     */
-    class AuthenticationMethodChangeListener implements ItemListener {
-        @Override
-        public void itemStateChanged(ItemEvent e) {
-            if (rbBasicAuthentication.isSelected()) {
-                pnlAuthenticationParameteters.removeAll();
-                pnlAuthenticationParameteters.add(pnlBasicAuthPreferences, BorderLayout.CENTER);
-                pnlBasicAuthPreferences.revalidate();
-            } else {
-                pnlAuthenticationParameteters.removeAll();
-                pnlAuthenticationParameteters.add(pnlOAuthPreferences, BorderLayout.CENTER);
-                pnlOAuthPreferences.revalidate();
-            }
-            repaint();
-        }
-    }
-
     @Override
     public void propertyChange(PropertyChangeEvent evt) {
-        if (pnlOAuthPreferences != null) {
-            pnlOAuthPreferences.propertyChange(evt);
+        /** TODO is this still necessary? */
+        if (pnlOAuthPreferences != null && !pnlOAuthPreferences.isEmpty()) {
+            for (OAuthAuthenticationPreferencesPanel panel : pnlOAuthPreferences) {
+                panel.propertyChange(evt);
+            }
         }
     }
 }
Index: src/org/openstreetmap/josm/gui/preferences/server/BasicAuthenticationPreferencesPanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/server/BasicAuthenticationPreferencesPanel.java	(revision 14995)
+++ src/org/openstreetmap/josm/gui/preferences/server/BasicAuthenticationPreferencesPanel.java	(working copy)
@@ -9,11 +9,16 @@
 import java.awt.Insets;
 import java.net.Authenticator.RequestorType;
 import java.net.PasswordAuthentication;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 import javax.swing.BorderFactory;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 
+import org.openstreetmap.josm.data.UserIdentityManager;
 import org.openstreetmap.josm.gui.widgets.JosmPasswordField;
 import org.openstreetmap.josm.gui.widgets.JosmTextField;
 import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
@@ -33,6 +38,10 @@
     private final JosmTextField tfOsmUserName = new JosmTextField();
     /** the OSM password */
     private final JosmPasswordField tfOsmPassword = new JosmPasswordField();
+    /** The password key in the user map */
+    public static final String KEY_PASSWORD = "password";
+    /** The username key in the user map */
+    public static final String KEY_USER = "login";
     /** a panel with further information, e.g. some warnings */
     private JPanel decorationPanel;
 
@@ -93,25 +102,39 @@
      * Inits contents from preferences.
      */
     public void initFromPreferences() {
-        CredentialsAgent cm = CredentialsManager.getInstance();
-        try {
-            decorationPanel.removeAll();
-            decorationPanel.add(cm.getPreferencesDecorationPanel(), BorderLayout.CENTER);
-            PasswordAuthentication pa = cm.lookup(RequestorType.SERVER, OsmApi.getOsmApi().getHost());
-            if (pa == null) {
-                tfOsmUserName.setText("");
-                tfOsmPassword.setText("");
-            } else {
-                tfOsmUserName.setText(pa.getUserName() == null ? "" : pa.getUserName());
-                tfOsmPassword.setText(pa.getPassword() == null ? "" : String.valueOf(pa.getPassword()));
+        initFromMap(null);
+    }
+
+    /**
+     * Initializes contents from a map
+     * @param user The map with the login/password
+     */
+    public void initFromMap(Map<String, String> user) {
+        if (user == null) {
+            user = new TreeMap<>();
+            CredentialsAgent cm = CredentialsManager.getInstance();
+            try {
+                decorationPanel.removeAll();
+                decorationPanel.add(cm.getPreferencesDecorationPanel(), BorderLayout.CENTER);
+                PasswordAuthentication pa = cm.lookup(RequestorType.SERVER, OsmApi.getOsmApi().getHost());
+                if (pa == null) {
+                    user.put(KEY_USER, "");
+                    user.put(KEY_PASSWORD, "");
+                } else {
+                    user.put("login", pa.getUserName() == null ? "" : pa.getUserName());
+                    user.put("password", pa.getPassword() == null ? "" : String.valueOf(pa.getPassword()));
+                }
+            } catch (CredentialsAgentException e) {
+                Logging.error(e);
+                Logging.warn(tr("Failed to retrieve OSM credentials from credential manager."));
+                Logging.warn(tr("Current credential manager is of type ''{0}''", cm.getClass().getName()));
+                user.put(KEY_USER, "");
+                user.put(KEY_PASSWORD, "");
             }
-        } catch (CredentialsAgentException e) {
-            Logging.error(e);
-            Logging.warn(tr("Failed to retrieve OSM credentials from credential manager."));
-            Logging.warn(tr("Current credential manager is of type ''{0}''", cm.getClass().getName()));
-            tfOsmUserName.setText("");
-            tfOsmPassword.setText("");
         }
+
+        tfOsmUserName.setText(user.get(KEY_USER) != null ? user.get(KEY_USER) : "");
+        tfOsmPassword.setText(user.get(KEY_PASSWORD) != null ? user.get(KEY_PASSWORD) : "");
     }
 
     /**
@@ -130,6 +153,25 @@
             Logging.warn(tr("Failed to save OSM credentials to credential manager."));
             Logging.warn(tr("Current credential manager is of type ''{0}''", cm.getClass().getName()));
         }
+        List<Map<String, String>> users = UserIdentityManager.getInstance().getUserAuthInformation();
+        boolean present = false;
+        for (Map<String, String> user : users) {
+            if (AuthenticationPreferencesPanel.AUTH_BASIC.equals(user.get(AuthenticationPreferencesPanel.AUTH_TYPE_KEY))
+                    && tfOsmUserName.getText().trim().equals(user.get(KEY_USER))) {
+                user.put(KEY_PASSWORD, Arrays.toString(tfOsmPassword.getPassword()));
+                user.put("url", OsmApi.getOsmApi().getHost());
+                present = true;
+                break;
+            }
+        }
+        if (!present) {
+            Map<String, String> map = new TreeMap<>();
+            map.put(KEY_USER, tfOsmUserName.getText().trim());
+            map.put(KEY_PASSWORD, tfOsmPassword.getParent().toString());
+            map.put("url", OsmApi.getOsmApi().getHost());
+            users.add(map);
+            UserIdentityManager.getInstance().saveUserAuthInformation(users);
+        }
     }
 
     /**
@@ -138,4 +180,35 @@
     public void clearPassword() {
         tfOsmPassword.setText("");
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof BasicAuthenticationPreferencesPanel)) return false;
+        BasicAuthenticationPreferencesPanel testPanel = (BasicAuthenticationPreferencesPanel) obj;
+        if (testPanel.tfOsmUserName.getText().equals(tfOsmUserName.getText())) return true;
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    /**
+     * Get the username in the field
+     * @return The username for this BasicAuthenticationPreference
+     * @since xxx
+     */
+    public String getUserName() {
+        return tfOsmUserName.getText();
+    }
+
+    /**
+     * Set the username in the field
+     * @param userName for this BasicAuthenticationPreference
+     * @since xxx
+     */
+    public void setUserName(String userName) {
+        tfOsmUserName.setText(userName);
+    }
 }
Index: src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java	(revision 14995)
+++ src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java	(working copy)
@@ -14,6 +14,8 @@
 import java.awt.event.ItemEvent;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.util.Map;
+import java.util.TreeMap;
 
 import javax.swing.AbstractAction;
 import javax.swing.BorderFactory;
@@ -51,7 +53,7 @@
     private final JPanel pnlAuthorisationMessage = new JPanel(new BorderLayout());
     private final NotYetAuthorisedPanel pnlNotYetAuthorised = new NotYetAuthorisedPanel();
     private final AdvancedOAuthPropertiesPanel pnlAdvancedProperties = new AdvancedOAuthPropertiesPanel();
-    private final AlreadyAuthorisedPanel pnlAlreadyAuthorised = new AlreadyAuthorisedPanel();
+    private final AlreadyAuthorisedPanel pnlAlreadyAuthorised = new AlreadyAuthorisedPanel(null);
     private String apiUrl;
 
     /**
@@ -125,10 +127,19 @@
     }
 
     protected void refreshView() {
+        Map<String, String> map = new TreeMap<>();
+        if (OAuthAccessTokenHolder.getInstance().containsAccessToken()) {
+            map.put("login", OAuthAccessTokenHolder.getInstance().getAccessTokenKey());
+            map.put("password", OAuthAccessTokenHolder.getInstance().getAccessTokenSecret());
+        }
+        refreshView(map);
+    }
+
+    protected void refreshView(Map<String, String> user) {
         pnlAuthorisationMessage.removeAll();
-        if (OAuthAccessTokenHolder.getInstance().containsAccessToken()) {
+        if (user.containsKey("login") && user.containsKey("password")) {
             pnlAuthorisationMessage.add(pnlAlreadyAuthorised, BorderLayout.CENTER);
-            pnlAlreadyAuthorised.refreshView();
+            pnlAlreadyAuthorised.refreshView(user);
             pnlAlreadyAuthorised.revalidate();
         } else {
             pnlAuthorisationMessage.add(pnlNotYetAuthorised, BorderLayout.CENTER);
@@ -156,6 +167,20 @@
     }
 
     /**
+     * Initializes the panel from a map
+     * @param user The map with a {@code login} and {@code password}.
+     * Optional information includes {@code url}.
+     */
+    public void initFromMap(Map<String, String> user) {
+        if (user.containsKey("url")) {
+            setApiUrl(user.get("url").trim());
+        } else {
+            setApiUrl(OsmApi.getOsmApi().getServerUrl().trim());
+        }
+        refreshView(user);
+    }
+
+    /**
      * Saves the current values to preferences
      */
     public void saveToPreferences() {
@@ -215,11 +240,19 @@
         private final JosmTextField tfAccessTokenSecret = new JosmTextField(null, null, 0, false);
 
         /**
-         * Constructs a new {@code AlreadyAuthorisedPanel}.
+         * Constructs a new {@code AlreadyAUthorisedPanel}.
+         * @param map The map with the authentication information
          */
-        AlreadyAuthorisedPanel() {
+        AlreadyAuthorisedPanel(Map<String, String> map) {
+            if (map == null) {
+                map = new TreeMap<>();
+                map.put("login", OAuthAccessTokenHolder.getInstance().getAccessTokenKey());
+                map.put("password", OAuthAccessTokenHolder.getInstance().getAccessTokenSecret());
+            }
+            tfAccessTokenKey.setText(map.get("login"));
+            tfAccessTokenSecret.setText(map.get("password"));
             build();
-            refreshView();
+            refreshView(map);
         }
 
         protected void build() {
@@ -291,10 +324,10 @@
             add(new JPanel(), gc);
         }
 
-        protected final void refreshView() {
-            String v = OAuthAccessTokenHolder.getInstance().getAccessTokenKey();
+        protected final void refreshView(Map<String, String> user) {
+            String v = user.get("login");
             tfAccessTokenKey.setText(v == null ? "" : v);
-            v = OAuthAccessTokenHolder.getInstance().getAccessTokenSecret();
+            v = user.get("password");
             tfAccessTokenSecret.setText(v == null ? "" : v);
             cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences());
         }
@@ -374,4 +407,24 @@
             return;
         setApiUrl((String) evt.getNewValue());
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof OAuthAuthenticationPreferencesPanel)) return false;
+        OAuthAuthenticationPreferencesPanel check = (OAuthAuthenticationPreferencesPanel) obj;
+        if (check.pnlAlreadyAuthorised == null && pnlAlreadyAuthorised == null) return true;
+        if ((check.pnlAlreadyAuthorised == null && pnlAlreadyAuthorised != null)
+                || (check.pnlAlreadyAuthorised != null && pnlAlreadyAuthorised == null)) return false;
+
+        if (check.pnlAlreadyAuthorised.tfAccessTokenKey.getText().equals(pnlAlreadyAuthorised.tfAccessTokenKey.getText())
+                && check.pnlAlreadyAuthorised.tfAccessTokenSecret.getText().equals(pnlAlreadyAuthorised.tfAccessTokenSecret.getText())) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
 }
Index: src/org/openstreetmap/josm/io/OsmConnection.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmConnection.java	(revision 14995)
+++ src/org/openstreetmap/josm/io/OsmConnection.java	(working copy)
@@ -104,18 +104,9 @@
      * Adds an authentication header for basic authentication
      *
      * @param con the connection
-     * @throws OsmTransferException if something went wrong. Check for nested exceptions
+     * @param response the response with username/password information
      */
-    protected void addBasicAuthorizationHeader(HttpClient con) throws OsmTransferException {
-        CredentialsAgentResponse response;
-        try {
-            synchronized (CredentialsManager.getInstance()) {
-                response = CredentialsManager.getInstance().getCredentials(RequestorType.SERVER,
-                con.getURL().getHost(), false /* don't know yet whether the credentials will succeed */);
-            }
-        } catch (CredentialsAgentException e) {
-            throw new OsmTransferException(e);
-        }
+    protected void addBasicAuthorizationHeader(HttpClient con, CredentialsAgentResponse response) {
         if (response != null) {
             if (response.isCanceled()) {
                 cancel = true;
@@ -132,16 +123,16 @@
      * Signs the connection with an OAuth authentication header
      *
      * @param connection the connection
+     * @param holder specific OAuth access token
      *
      * @throws MissingOAuthAccessTokenException if there is currently no OAuth Access Token configured
      * @throws OsmTransferException if signing fails
      */
-    protected void addOAuthAuthorizationHeader(HttpClient connection) throws OsmTransferException {
+    protected void addOAuthAuthorizationHeader(HttpClient connection, OAuthAccessTokenHolder holder) throws OsmTransferException {
         if (oauthParameters == null) {
             oauthParameters = OAuthParameters.createFromApiUrl(OsmApi.getOsmApi().getServerUrl());
         }
         OAuthConsumer consumer = oauthParameters.buildConsumer();
-        OAuthAccessTokenHolder holder = OAuthAccessTokenHolder.getInstance();
         if (!holder.containsAccessToken()) {
             obtainAccessToken(connection);
         }
@@ -177,13 +168,45 @@
     }
 
     protected void addAuth(HttpClient connection) throws OsmTransferException {
-        final String authMethod = OsmApi.getAuthMethod();
-        if ("basic".equals(authMethod)) {
-            addBasicAuthorizationHeader(connection);
-        } else if ("oauth".equals(authMethod)) {
-            addOAuthAuthorizationHeader(connection);
+        addAuth(connection, null);
+    }
+
+    /**
+     * Add authorization information to a connection
+     * @param connection to add authorization information to
+     * @param holder A {@code CredentialsAgentResponse} for basic authorization,
+     * {@code OAuthAccessTokenHolder} for OAuth, or {@code null} for defaults.
+     * @throws OsmTransferException if the authorization is not valid
+     */
+    protected void addAuth(HttpClient connection, Object holder) throws OsmTransferException {
+        if (holder == null) {
+            final String authMethod = OsmApi.getAuthMethod();
+            if ("basic".equals(authMethod)) {
+                CredentialsAgentResponse response;
+                try {
+                    synchronized (CredentialsManager.getInstance()) {
+                        response = CredentialsManager.getInstance().getCredentials(RequestorType.SERVER,
+                        connection.getURL().getHost(), false /* don't know yet whether the credentials will succeed */);
+                    }
+                } catch (CredentialsAgentException e) {
+                    throw new OsmTransferException(e);
+                }
+                holder = response;
+            } else if ("oauth".equals(authMethod)) {
+                holder = OAuthAccessTokenHolder.getInstance();
+            } else {
+                String msg = tr("Unexpected value for preference ''{0}''. Got ''{1}''.", "osm-server.auth-method", authMethod);
+                Logging.warn(msg);
+                throw new OsmTransferException(msg);
+            }
+        }
+
+        if (holder instanceof OAuthAccessTokenHolder) {
+            addOAuthAuthorizationHeader(connection, (OAuthAccessTokenHolder) holder);
+        } else if (holder instanceof CredentialsAgentResponse) {
+            addBasicAuthorizationHeader(connection, (CredentialsAgentResponse) holder);
         } else {
-            String msg = tr("Unexpected value for preference ''{0}''. Got ''{1}''.", "osm-server.auth-method", authMethod);
+            String msg = tr("Unexpected object for authorizations. Got ''{0}''.", holder.getClass().getName());
             Logging.warn(msg);
             throw new OsmTransferException(msg);
         }
Index: src/org/openstreetmap/josm/io/OsmServerReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 14995)
+++ src/org/openstreetmap/josm/io/OsmServerReader.java	(working copy)
@@ -79,10 +79,27 @@
      * @throws OsmTransferException if data transfer errors occur
      */
     protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor, String reason) throws OsmTransferException {
+        return getInputStream(urlStr, progressMonitor, reason, null);
+    }
+
+    /**
+     * Open a connection to the given url and return a reader on the input stream
+     * from that connection. In case of user cancel, return <code>null</code>.
+     * Relative URL's are directed to API base URL.
+     * @param urlStr The url to connect to.
+     * @param progressMonitor progress monitoring and abort handler
+     * @param reason The reason to show on console. Can be {@code null} if no reason is given
+     * @param authentication A {@code CredentialsAgentResponse} for basic authorization,
+     * {@code OAuthAccessTokenHolder} for OAuth, or {@code null} for defaults.
+     * @return A reader reading the input stream (servers answer) or <code>null</code>.
+     * @throws OsmTransferException if data transfer errors occur
+     */
+    protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor, String reason, Object authentication)
+            throws OsmTransferException {
         try {
             api.initialize(progressMonitor);
             String url = urlStr.startsWith("http") ? urlStr : (getBaseUrl() + urlStr);
-            return getInputStreamRaw(url, progressMonitor, reason);
+            return getInputStreamRaw(url, progressMonitor, reason, authentication);
         } finally {
             progressMonitor.invalidate();
         }
@@ -122,6 +139,21 @@
     }
 
     /**
+     * Open a connection to the given url and return a reader on the input stream
+     * from that connection. In case of user cancel, return <code>null</code>.
+     * @param urlStr The exact url to connect to.
+     * @param progressMonitor progress monitoring and abort handler
+     * @param reason The reason to show on console. Can be {@code null} if no reason is given
+     * @return An reader reading the input stream (servers answer) or <code>null</code>.
+     * @throws OsmTransferException if data transfer errors occur
+     * @since xxx
+     */
+    protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason, Object auth)
+            throws OsmTransferException {
+        return getInputStreamRaw(urlStr, progressMonitor, reason, false, "GET", null, auth);
+    }
+
+    /**
      * Open a connection to the given url (if HTTP, trough a GET request) and return a reader on the input stream
      * from that connection. In case of user cancel, return <code>null</code>.
      * @param urlStr The exact url to connect to.
@@ -151,9 +183,31 @@
      * @throws OsmTransferException if data transfer errors occur
      * @since 12596
      */
+    protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason,
+            boolean uncompressAccordingToContentDisposition, String httpMethod, byte[] requestBody) throws OsmTransferException {
+        return getInputStreamRaw(urlStr, progressMonitor, reason, uncompressAccordingToContentDisposition, httpMethod, requestBody, null);
+    }
+
+    /**
+     * Open a connection to the given url (if HTTP, with the specified method) and return a reader on the input stream
+     * from that connection. In case of user cancel, return <code>null</code>.
+     * @param urlStr The exact url to connect to.
+     * @param progressMonitor progress monitoring and abort handler
+     * @param reason The reason to show on console. Can be {@code null} if no reason is given
+     * @param uncompressAccordingToContentDisposition Whether to inspect the HTTP header {@code Content-Disposition}
+     *                                                for {@code filename} and uncompress a gzip/bzip2/xz/zip stream.
+     * @param httpMethod HTTP method ("GET", "POST" or "PUT")
+     * @param requestBody HTTP request body (for "POST" and "PUT" methods only). Must be null for "GET" method.
+     * @param auth A {@code CredentialsAgentResponse} for basic authorization,
+     * {@code OAuthAccessTokenHolder} for OAuth, or {@code null} for defaults.
+     * @return An reader reading the input stream (servers answer) or {@code null}.
+     * @throws OsmTransferException if data transfer errors occur
+     * @since xxx
+     */
     @SuppressWarnings("resource")
     protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason,
-            boolean uncompressAccordingToContentDisposition, String httpMethod, byte[] requestBody) throws OsmTransferException {
+            boolean uncompressAccordingToContentDisposition, String httpMethod, byte[] requestBody,
+            Object auth) throws OsmTransferException {
         try {
             OnlineResource.JOSM_WEBSITE.checkOfflineAccess(urlStr, Config.getUrls().getJOSMWebsite());
             OnlineResource.OSM_API.checkOfflineAccess(urlStr, OsmApi.getOsmApi().getServerUrl());
@@ -182,7 +236,7 @@
             activeConnection = client;
             adaptRequest(client);
             if (doAuthenticate) {
-                addAuth(client);
+                addAuth(client, auth);
             }
             if (cancel)
                 throw new OsmTransferCanceledException("Operation canceled");
@@ -415,10 +469,29 @@
      */
     public <T> T fetchData(String api, String subtask, DomParser<T> parser, ProgressMonitor monitor, String reason)
             throws OsmTransferException {
+        return fetchData(api, subtask, parser, monitor, reason, null);
+    }
+
+    /**
+     * Fetches generic data from the DOM document resulting an API call.
+     * @param api the OSM API call
+     * @param subtask the subtask translated message
+     * @param parser the parser converting the DOM document (OSM API result)
+     * @param <T> data type
+     * @param monitor The progress monitor
+     * @param reason The reason to show on console. Can be {@code null} if no reason is given
+     * @param authentication A {@code CredentialsAgentResponse} for basic authorization,
+     * {@code OAuthAccessTokenHolder} for OAuth, or {@code null} for defaults.
+     * @return The converted data
+     * @throws OsmTransferException if something goes wrong
+     * @since 12510
+     */
+    public <T> T fetchData(String api, String subtask, DomParser<T> parser, ProgressMonitor monitor, String reason, Object authentication)
+            throws OsmTransferException {
         try {
             monitor.beginTask("");
             monitor.indeterminateSubTask(subtask);
-            try (InputStream in = getInputStream(api, monitor.createSubTaskMonitor(1, true), reason)) {
+            try (InputStream in = getInputStream(api, monitor.createSubTaskMonitor(1, true), reason, authentication)) {
                 return parser.parse(XmlUtils.parseSafeDOM(in));
             }
         } catch (OsmTransferException e) {
Index: src/org/openstreetmap/josm/io/OsmServerUserInfoReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerUserInfoReader.java	(revision 14995)
+++ src/org/openstreetmap/josm/io/OsmServerUserInfoReader.java	(working copy)
@@ -13,9 +13,12 @@
 import javax.xml.xpath.XPathFactory;
 
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.UserInfo;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.auth.CredentialsAgentResponse;
+import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.UncheckedParseException;
 import org.openstreetmap.josm.tools.XmlParsingException;
 import org.openstreetmap.josm.tools.date.DateUtils;
@@ -159,6 +162,23 @@
     }
 
     /**
+     * Fetches user info without explicit reason with a specific authentication
+     * @param monitor The progress monitor
+     * @param authentication The authentication object ({@code OAuthAccessTokenHolder}
+     * or {@code CredentialsAgentResponse})
+     * @return The user info
+     * @throws OsmTransferException if something goes wrong
+     * @since xxx
+     */
+    public UserInfo fetchUserInfo(ProgressMonitor monitor, Object authentication) throws OsmTransferException {
+        if (authentication instanceof String) {
+            return fetchUserInfo(monitor, null, (String) authentication);
+        } else {
+            return fetchUserInfo(monitor, authentication, null);
+        }
+    }
+
+    /**
      * Fetches user info, with an explicit reason.
      * @param monitor The progress monitor
      * @param reason The reason to show on console. Can be {@code null} if no reason is given
@@ -167,7 +187,28 @@
      * @since 6695
      */
     public UserInfo fetchUserInfo(ProgressMonitor monitor, String reason) throws OsmTransferException {
-        return fetchData("user/details", tr("Reading user info ..."),
-                OsmServerUserInfoReader::buildFromXML, monitor, reason);
+        return fetchUserInfo(monitor, null, reason);
     }
+
+    /**
+     * Fetches user info, with an explicit reason.
+     * @param monitor The progress monitor
+     * @param authentication A {@code CredentialsAgentResponse} for basic authorization,
+     * {@code OAuthAccessTokenHolder} for OAuth, or {@code null} for defaults.
+     * @param reason The reason to show on console. Can be {@code null} if no reason is given
+     * @return The user info
+     * @throws OsmTransferException if something goes wrong
+     * @since xxx
+     */
+    public UserInfo fetchUserInfo(ProgressMonitor monitor, Object authentication, String reason) throws OsmTransferException {
+        if (authentication instanceof OAuthAccessTokenHolder || authentication instanceof CredentialsAgentResponse
+                || authentication == null) {
+            return fetchData("user/details", tr("Reading user info ..."),
+                    OsmServerUserInfoReader::buildFromXML, monitor, reason, authentication);
+        } else {
+            String msg = tr("We did not get a valid authentication object ({0})", authentication.getClass().getName());
+            Logging.warn(msg);
+            throw new OsmTransferException(msg);
+        }
+    }
 }
