Index: src/org/openstreetmap/josm/data/UserIdentityManager.java
===================================================================
--- src/org/openstreetmap/josm/data/UserIdentityManager.java	(revision 14962)
+++ 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,98 @@
     }
 
     /**
+     * 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() {
+        if ("oauth".equals(Config.getPref().get("osm-server.auth-method"))) {
+            return getDefaultOAuthList();
+        } else {
+            return getDefaultBasicAuthList();
+        }
+    }
+
+    /**
+     * 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 +366,34 @@
         }
     }
 
+    /**
+     * 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;
+    }
+
     /* ------------------------------------------------------------------- */
     /* interface PreferenceChangeListener                                  */
     /* ------------------------------------------------------------------- */
Index: src/org/openstreetmap/josm/data/oauth/OAuthAccessTokenHolder.java
===================================================================
--- src/org/openstreetmap/josm/data/oauth/OAuthAccessTokenHolder.java	(revision 14962)
+++ 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 14962)
+++ 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 14962)
+++ src/org/openstreetmap/josm/gui/preferences/server/AuthenticationPreferencesPanel.java	(working copy)
@@ -7,21 +7,23 @@
 import java.awt.GridBagConstraints;
 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.AbstractAction;
 import javax.swing.ButtonGroup;
+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.Logging;
 
@@ -31,16 +33,16 @@
  */
 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();
+    /** add a OAuth method */
+    private final JButton rbOAuth = new JButton();
     /** 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;
+    /** 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;
 
@@ -60,7 +62,13 @@
         setLayout(new GridBagLayout());
         GridBagConstraints gc = new GridBagConstraints();
 
-        AuthenticationMethodChangeListener authChangeListener = new AuthenticationMethodChangeListener();
+        //-- the panel for API feature preferences
+        int tGridy = gc.gridy;
+        gc.gridy = 3;
+        gc.fill = GridBagConstraints.NONE;
+        pnlFeaturesPreferences = new FeaturesPanel();
+        add(pnlFeaturesPreferences, gc);
+        gc.gridy = tGridy;
 
         // -- radio button for basic authentication
         gc.anchor = GridBagConstraints.NORTHWEST;
@@ -69,17 +77,35 @@
         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.setText(tr("Add Basic Authentication"));
+        rbBasicAuthentication.setToolTipText(tr("Select to add HTTP basic authentication with your OSM username and password"));
+        rbBasicAuthentication.setAction(new AbstractAction() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                BasicAuthenticationPreferencesPanel panel = new BasicAuthenticationPreferencesPanel();
+                panel.initFromPreferences();
+                pnlBasicAuthPreferences.add(panel);
+                pnlAuthenticationParameteters.add(panel, BorderLayout.CENTER);
+                repaint();
+            }
+        });
 
         //-- 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.setText(tr("Add OAuth"));
+        rbOAuth.setToolTipText(tr("Select to add a OAuth authentication mechanism"));
+        rbOAuth.setAction(new AbstractAction() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                OAuthAuthenticationPreferencesPanel panel = new OAuthAuthenticationPreferencesPanel();
+                panel.initFromPreferences();
+                pnlOAuthPreferences.add(panel);
+                pnlAuthenticationParameteters.add(panel, BorderLayout.CENTER);
+                repaint();
+            }
+        });
 
         //-- radio button for OAuth
         ButtonGroup bg = new ButtonGroup();
@@ -96,20 +122,31 @@
         add(pnlAuthenticationParameteters, gc);
 
         //-- 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);
+    }
 
-        //-- the panel for API feature preferences
-        gc.gridy = 3;
-        gc.fill = GridBagConstraints.NONE;
-        pnlFeaturesPreferences = new FeaturesPanel();
-        add(pnlFeaturesPreferences, gc);
+    private void populateAuthPanels() {
+        List<Map<String, String>> users = UserIdentityManager.getInstance().getUserAuthInformation();
+        for (Map<String, String> user : users) {
+            if ("oauth".equals(user.get("auth-type"))) {
+                OAuthAuthenticationPreferencesPanel panel = new OAuthAuthenticationPreferencesPanel();
+                panel.initFromMap(user);
+                pnlOAuthPreferences.add(panel);
+                pnlAuthenticationParameteters.add(panel);
+            } else if ("basic".equals(user.get("auth-type"))) {
+                BasicAuthenticationPreferencesPanel panel = new BasicAuthenticationPreferencesPanel();
+                panel.initFromMap(user);
+                pnlBasicAuthPreferences.add(panel);
+                pnlAuthenticationParameteters.add(panel);
+            }
+        }
+        repaint();
     }
 
     /**
@@ -126,8 +163,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 ("oauth".equals(user.get("auth-type"))) {
+                OAuthAuthenticationPreferencesPanel panel = new OAuthAuthenticationPreferencesPanel();
+                panel.initFromMap(user);
+                pnlOAuthPreferences.add(panel);
+            } else if ("basic".equals(user.get("auth-type"))) {
+                BasicAuthenticationPreferencesPanel panel = new BasicAuthenticationPreferencesPanel();
+                panel.initFromMap(user);
+                pnlBasicAuthPreferences.add(panel);
+            }
+        }
         pnlFeaturesPreferences.initFromPreferences();
     }
 
@@ -143,44 +190,23 @@
             authMethod = "oauth";
         }
         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 14962)
+++ src/org/openstreetmap/josm/gui/preferences/server/BasicAuthenticationPreferencesPanel.java	(working copy)
@@ -9,11 +9,15 @@
 import java.awt.Insets;
 import java.net.Authenticator.RequestorType;
 import java.net.PasswordAuthentication;
+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;
@@ -93,25 +97,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("login", "");
+                    user.put("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("login",  "");
+                user.put("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("login") != null ? user.get("login") : "");
+        tfOsmPassword.setText(user.get("password") != null ? user.get("password") : "");
     }
 
     /**
@@ -130,6 +148,24 @@
             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 ("basic".equals(user.get("auth-type"))) {
+                if (tfOsmUserName.getText().trim().equals(user.get("login"))) {
+                    user.put("password", tfOsmPassword.getPassword().toString());
+                    user.put("url", OsmApi.getOsmApi().getHost());
+                    present = true;
+                    break;
+                }
+            }
+        }
+        if (!present) {
+            Map<String, String> map = new TreeMap<>();
+            map.put("login", tfOsmUserName.getText().trim());
+            map.put("password", tfOsmPassword.getParent().toString());
+            map.put("url", OsmApi.getOsmApi().getHost());
+        }
     }
 
     /**
Index: src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java
===================================================================
--- src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java	(revision 14962)
+++ 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();
 
         /**
-         * 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());
         }
Index: src/org/openstreetmap/josm/io/OsmConnection.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmConnection.java	(revision 14962)
+++ 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 14962)
+++ src/org/openstreetmap/josm/io/OsmServerReader.java	(working copy)
@@ -79,10 +79,26 @@
      * @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 +138,20 @@
     }
 
     /**
+     * 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 +181,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 +234,7 @@
             activeConnection = client;
             adaptRequest(client);
             if (doAuthenticate) {
-                addAuth(client);
+                addAuth(client, auth);
             }
             if (cancel)
                 throw new OsmTransferCanceledException("Operation canceled");
@@ -415,10 +467,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 14962)
+++ 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);
+        }
+    }
 }
