Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java	(revision 31457)
@@ -2,5 +2,5 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.plugins.mapillary.cache.Utils;
+import org.openstreetmap.josm.plugins.mapillary.cache.CacheUtils;
 import org.openstreetmap.josm.plugins.mapillary.gui.MapillaryMainDialog;
 
@@ -173,19 +173,11 @@
    * following visible MapillaryImage is selected. In case there is none, does
    * nothing.
+   *
+   * @throws IllegalStateException
+   *           if the selected image is null or the selected image doesn't
+   *           belong to a sequence.
    */
   public void selectNext() {
-    if (getSelectedImage() == null)
-      return;
-    if (getSelectedImage().getSequence() == null)
-      return;
-    MapillaryAbstractImage tempImage = this.selectedImage;
-    while (tempImage.next() != null) {
-      tempImage = tempImage.next();
-      if (tempImage.isVisible()) {
-        setSelectedImage(tempImage,
-            Main.pref.getBoolean("mapillary.move-to-picture", true));
-        break;
-      }
-    }
+    selectNext(Main.pref.getBoolean("mapillary.move-to-picture", true));
   }
 
@@ -197,10 +189,13 @@
    * @param moveToPicture
    *          True if the view must me moved to the next picture.
+   * @throws IllegalStateException
+   *           if the selected image is null or the selected image doesn't
+   *           belong to a sequence.
    */
   public void selectNext(boolean moveToPicture) {
     if (getSelectedImage() == null)
-      return;
+      throw new IllegalStateException();
     if (getSelectedImage().getSequence() == null)
-      return;
+      throw new IllegalStateException();
     MapillaryAbstractImage tempImage = this.selectedImage;
     while (tempImage.next() != null) {
@@ -217,19 +212,11 @@
    * previous visible MapillaryImage is selected. In case there is none, does
    * nothing.
+   *
+   * @throws IllegalStateException
+   *           if the selected image is null or the selected image doesn't
+   *           belong to a sequence.
    */
   public void selectPrevious() {
-    if (getSelectedImage() == null)
-      return;
-    if (getSelectedImage().getSequence() == null)
-      throw new IllegalStateException();
-    MapillaryAbstractImage tempImage = this.selectedImage;
-    while (tempImage.previous() != null) {
-      tempImage = tempImage.previous();
-      if (tempImage.isVisible()) {
-        setSelectedImage(tempImage,
-            Main.pref.getBoolean("mapillary.move-to-picture", true));
-        break;
-      }
-    }
+    selectPrevious(Main.pref.getBoolean("mapillary.move-to-picture", true));
   }
 
@@ -237,8 +224,12 @@
    * If the selected MapillaryImage is part of a MapillarySequence then the
    * previous visible MapillaryImage is selected. In case there is none, does
-   * nothing.
+   * nothing. * @throws IllegalStateException if the selected image is null or
+   * the selected image doesn't belong to a sequence.
    *
    * @param moveToPicture
    *          True if the view must me moved to the previous picture.
+   * @throws IllegalStateException
+   *           if the selected image is null or the selected image doesn't
+   *           belong to a sequence.
    */
   public void selectPrevious(boolean moveToPicture) {
@@ -262,4 +253,5 @@
    * @param image
    *          The MapillaryImage which is going to be selected
+   *
    */
   public void setSelectedImage(MapillaryAbstractImage image) {
@@ -286,13 +278,13 @@
         // Downloading thumbnails of surrounding pictures.
         if (mapillaryImage.next() != null) {
-          Utils.downloadPicture((MapillaryImage) mapillaryImage.next());
+          CacheUtils.downloadPicture((MapillaryImage) mapillaryImage.next());
           if (mapillaryImage.next().next() != null)
-            Utils
+            CacheUtils
                 .downloadPicture((MapillaryImage) mapillaryImage.next().next());
         }
         if (mapillaryImage.previous() != null) {
-          Utils.downloadPicture((MapillaryImage) mapillaryImage.previous());
+          CacheUtils.downloadPicture((MapillaryImage) mapillaryImage.previous());
           if (mapillaryImage.previous().previous() != null)
-            Utils.downloadPicture((MapillaryImage) mapillaryImage.previous()
+            CacheUtils.downloadPicture((MapillaryImage) mapillaryImage.previous()
                 .previous());
         }
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImportedImage.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImportedImage.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImportedImage.java	(revision 31457)
@@ -69,5 +69,5 @@
    */
   public BufferedImage getImage() throws IOException {
-    return this.file == null ? null : ImageIO.read(this.file);
+    return ImageIO.read(this.file);
   }
 
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java	(revision 31457)
@@ -4,5 +4,5 @@
 import static org.openstreetmap.josm.tools.I18n.marktr;
 
-import org.openstreetmap.josm.plugins.mapillary.cache.Utils;
+import org.openstreetmap.josm.plugins.mapillary.cache.CacheUtils;
 import org.openstreetmap.josm.plugins.mapillary.downloads.MapillaryDownloader;
 import org.openstreetmap.josm.plugins.mapillary.gui.MapillaryFilterDialog;
@@ -278,6 +278,5 @@
     if (Main.map.mapView.getActiveLayer() == this) {
       Rectangle b = mv.getBounds();
-      // on some platforms viewport bounds seem to be offset from the
-      // left,
+      // on some platforms viewport bounds seem to be offset from the left,
       // over-grow it just to be sure
       b.grow(100, 100);
@@ -486,7 +485,7 @@
     // Predownloads the thumbnails
     if (ret[0] != null)
-      Utils.downloadPicture(ret[0]);
+      CacheUtils.downloadPicture(ret[0]);
     if (ret[1] != null)
-      Utils.downloadPicture(ret[1]);
+      CacheUtils.downloadPicture(ret[1]);
     return ret;
   }
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryPlugin.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryPlugin.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryPlugin.java	(revision 31457)
@@ -20,4 +20,5 @@
 import org.openstreetmap.josm.plugins.mapillary.gui.MapillaryPreferenceSetting;
 import org.openstreetmap.josm.plugins.mapillary.gui.MapillaryMainDialog;
+import org.openstreetmap.josm.plugins.mapillary.oauth.MapillaryUser;
 import org.openstreetmap.josm.plugins.mapillary.actions.*;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -142,4 +143,7 @@
       Main.error(e);
     }
+
+    if (Main.pref.get("mapillary.access-token") == null)
+      MapillaryUser.isTokenValid = false;
   }
 
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java	(revision 31457)
@@ -107,4 +107,7 @@
    *          going to be returned.
    * @return The next {@link MapillaryAbstractImage} object in the sequence.
+   * @throws IllegalArgumentException
+   *           if the given {@link MapillaryAbstractImage} object doesn't belong
+   *           the this sequence.
    */
   public MapillaryAbstractImage next(MapillaryAbstractImage image) {
@@ -124,4 +127,7 @@
    *          going to be returned.
    * @return The previous {@link MapillaryAbstractImage} object in the sequence.
+   * @throws IllegalArgumentException
+   *           if the given {@link MapillaryAbstractImage} object doesn't belong
+   *           the this sequence.
    */
   public MapillaryAbstractImage previous(MapillaryAbstractImage image) {
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/WalkThread.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/WalkThread.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/WalkThread.java	(revision 31457)
@@ -12,5 +12,5 @@
 import org.openstreetmap.josm.plugins.mapillary.MapillaryImage;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryLayer;
-import org.openstreetmap.josm.plugins.mapillary.cache.Utils;
+import org.openstreetmap.josm.plugins.mapillary.cache.CacheUtils;
 import org.openstreetmap.josm.plugins.mapillary.gui.MapillaryMainDialog;
 
@@ -66,6 +66,6 @@
               break;
             image = image.next();
-            Utils.downloadPicture((MapillaryImage) image,
-                Utils.PICTURE.THUMBNAIL);
+            CacheUtils.downloadPicture((MapillaryImage) image,
+                CacheUtils.PICTURE.THUMBNAIL);
           }
           if (this.waitForFullQuality)
@@ -75,6 +75,6 @@
                 break;
               image = image.next();
-              Utils.downloadPicture((MapillaryImage) image,
-                  Utils.PICTURE.FULL_IMAGE);
+              CacheUtils.downloadPicture((MapillaryImage) image,
+                  CacheUtils.PICTURE.FULL_IMAGE);
             }
         }
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/CacheUtils.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/CacheUtils.java	(revision 31457)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/CacheUtils.java	(revision 31457)
@@ -0,0 +1,79 @@
+package org.openstreetmap.josm.plugins.mapillary.cache;
+
+import org.openstreetmap.josm.data.cache.CacheEntry;
+import org.openstreetmap.josm.data.cache.CacheEntryAttributes;
+import org.openstreetmap.josm.data.cache.ICachedLoaderListener;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImage;
+
+/**
+ * Utility methods for working with cache.
+ *
+ * @author nokutu
+ *
+ */
+public class CacheUtils {
+
+  private static IgnoreDownload IGNORE_DOWNLOAD = new IgnoreDownload();
+
+  /** Picture quality */
+  public enum PICTURE {
+    /** Thumbnail quality picture (320 p) */
+    THUMBNAIL,
+    /** Full quality picture (2048 p) */
+    FULL_IMAGE,
+    /** Both of them */
+    BOTH;
+  }
+
+  /**
+   * Downloads the the thumbnail and the full resolution picture of the given
+   * image. Does nothing if it is already in cache.
+   *
+   * @param img
+   *          The image whose picture is going to be downloaded.
+   */
+  public static void downloadPicture(MapillaryImage img) {
+    downloadPicture(img, PICTURE.BOTH);
+  }
+
+  /**
+   * Downloads the picture of the given image. Does nothing when it is already
+   * in cache.
+   *
+   * @param img The image to be downloaded.
+   * @param pic
+   *          The picture type to be downloaded (full quality, thumbnail or
+   *          both.)
+   */
+  public static void downloadPicture(MapillaryImage img, PICTURE pic) {
+    switch (pic) {
+      case BOTH:
+        if (new MapillaryCache(img.getKey(), MapillaryCache.Type.THUMBNAIL)
+            .get() == null)
+          new MapillaryCache(img.getKey(), MapillaryCache.Type.THUMBNAIL)
+              .submit(IGNORE_DOWNLOAD, false);
+        if (new MapillaryCache(img.getKey(), MapillaryCache.Type.FULL_IMAGE)
+            .get() == null)
+          new MapillaryCache(img.getKey(), MapillaryCache.Type.FULL_IMAGE)
+              .submit(IGNORE_DOWNLOAD, false);
+        break;
+      case THUMBNAIL:
+        new MapillaryCache(img.getKey(), MapillaryCache.Type.THUMBNAIL).submit(
+            IGNORE_DOWNLOAD, false);
+        break;
+      case FULL_IMAGE:
+        new MapillaryCache(img.getKey(), MapillaryCache.Type.FULL_IMAGE)
+            .submit(IGNORE_DOWNLOAD, false);
+        break;
+    }
+  }
+
+  private static class IgnoreDownload implements ICachedLoaderListener {
+
+    @Override
+    public void loadingFinished(CacheEntry arg0, CacheEntryAttributes arg1,
+        LoadResult arg2) {
+      // Nothing
+    }
+  }
+}
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/Utils.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/Utils.java	(revision 31456)
+++ 	(revision )
@@ -1,79 +1,0 @@
-package org.openstreetmap.josm.plugins.mapillary.cache;
-
-import org.openstreetmap.josm.data.cache.CacheEntry;
-import org.openstreetmap.josm.data.cache.CacheEntryAttributes;
-import org.openstreetmap.josm.data.cache.ICachedLoaderListener;
-import org.openstreetmap.josm.plugins.mapillary.MapillaryImage;
-
-/**
- * Utility methods for working with cache.
- *
- * @author nokutu
- *
- */
-public class Utils {
-
-  private static IgnoreDownload IGNORE_DOWNLOAD = new IgnoreDownload();
-
-  /** Picture quality */
-  public enum PICTURE {
-    /** Thumbnail quality picture (320 p) */
-    THUMBNAIL,
-    /** Full quality picture (2048 p) */
-    FULL_IMAGE,
-    /** Both of them */
-    BOTH;
-  }
-
-  /**
-   * Downloads the the thumbnail and the full resolution picture of the given
-   * image. Does nothing if it is already in cache.
-   *
-   * @param img
-   *          The image whose picture is going to be downloaded.
-   */
-  public static void downloadPicture(MapillaryImage img) {
-    downloadPicture(img, PICTURE.BOTH);
-  }
-
-  /**
-   * Downloads the picture of the given image. Does nothing when it is already
-   * in cache.
-   *
-   * @param img The image to be downloaded.
-   * @param pic
-   *          The picture type to be downloaded (full quality, thumbnail or
-   *          both.)
-   */
-  public static void downloadPicture(MapillaryImage img, PICTURE pic) {
-    switch (pic) {
-      case BOTH:
-        if (new MapillaryCache(img.getKey(), MapillaryCache.Type.THUMBNAIL)
-            .get() == null)
-          new MapillaryCache(img.getKey(), MapillaryCache.Type.THUMBNAIL)
-              .submit(IGNORE_DOWNLOAD, false);
-        if (new MapillaryCache(img.getKey(), MapillaryCache.Type.FULL_IMAGE)
-            .get() == null)
-          new MapillaryCache(img.getKey(), MapillaryCache.Type.FULL_IMAGE)
-              .submit(IGNORE_DOWNLOAD, false);
-        break;
-      case THUMBNAIL:
-        new MapillaryCache(img.getKey(), MapillaryCache.Type.THUMBNAIL).submit(
-            IGNORE_DOWNLOAD, false);
-        break;
-      case FULL_IMAGE:
-        new MapillaryCache(img.getKey(), MapillaryCache.Type.FULL_IMAGE)
-            .submit(IGNORE_DOWNLOAD, false);
-        break;
-    }
-  }
-
-  private static class IgnoreDownload implements ICachedLoaderListener {
-
-    @Override
-    public void loadingFinished(CacheEntry arg0, CacheEntryAttributes arg1,
-        LoadResult arg2) {
-      // Nothing
-    }
-  }
-}
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryMainDialog.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryMainDialog.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryMainDialog.java	(revision 31457)
@@ -269,4 +269,5 @@
   }
 
+  /** Disables all the buttons in the dialog */
   private void disableAllButtons() {
     this.nextButton.setEnabled(false);
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryPreferenceSetting.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryPreferenceSetting.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryPreferenceSetting.java	(revision 31457)
@@ -7,5 +7,4 @@
 import java.awt.event.ActionEvent;
 import java.io.IOException;
-import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -44,4 +43,5 @@
   private JCheckBox moveTo = new JCheckBox(
       tr("Move to picture's location with next/previous buttons"));
+  private JButton login;
 
   @Override
@@ -56,8 +56,9 @@
     this.reverseButtons.setSelected(Main.pref
         .getBoolean("mapillary.reverse-buttons"));
-    this.displayHour.setSelected(Main.pref
-        .getBoolean("mapillary.display-hour", true));
+    this.displayHour.setSelected(Main.pref.getBoolean("mapillary.display-hour",
+        true));
     this.format24.setSelected(Main.pref.getBoolean("mapillary.format-24"));
-    this.moveTo.setSelected(Main.pref.getBoolean("mapillary.move-to-picture", true));
+    this.moveTo.setSelected(Main.pref.getBoolean("mapillary.move-to-picture",
+        true));
 
     panel.setLayout(new FlowLayout(FlowLayout.LEFT));
@@ -82,18 +83,18 @@
     panel.add(this.format24);
     panel.add(this.moveTo);
-    JButton oauth = new JButton(new OAuthAction());
+    this.login = new JButton(new LoginAction());
     if (Main.pref.get("mapillary.access-token") == null)
-      oauth.setText("Login");
+      this.login.setText("Login");
     else
-      try {
-        oauth.setText("Logged as: " + MapillaryUser.getUsername() + ". Click to relogin.");
-      } catch (MalformedURLException e) {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
-      } catch (IOException e) {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
-      }
-    panel.add(oauth);
+      this.login.setText("Logged as: " + MapillaryUser.getUsername()
+          + ". Click to relogin.");
+
+    panel.add(this.login);
+    if (MapillaryUser.getUsername() != null) {
+      JButton logout = new JButton(new LogoutAction());
+      logout.setText("Logout");
+
+      panel.add(logout);
+    }
     gui.getDisplayPreference().addSubTab(this, "Mapillary", panel);
   }
@@ -102,12 +103,16 @@
   public boolean ok() {
     boolean mod = false;
-    Main.pref.put("mapillary.reverse-buttons", this.reverseButtons.isSelected());
+    Main.pref
+        .put("mapillary.reverse-buttons", this.reverseButtons.isSelected());
 
     MapillaryPlugin.setMenuEnabled(MapillaryPlugin.DOWNLOAD_VIEW_MENU, false);
-    if (this.downloadMode.getSelectedItem().equals(MapillaryDownloader.MODES[0]))
+    if (this.downloadMode.getSelectedItem()
+        .equals(MapillaryDownloader.MODES[0]))
       Main.pref.put("mapillary.download-mode", MapillaryDownloader.MODES[0]);
-    if (this.downloadMode.getSelectedItem().equals(MapillaryDownloader.MODES[1]))
+    if (this.downloadMode.getSelectedItem()
+        .equals(MapillaryDownloader.MODES[1]))
       Main.pref.put("mapillary.download-mode", MapillaryDownloader.MODES[1]);
-    if (this.downloadMode.getSelectedItem().equals(MapillaryDownloader.MODES[2])) {
+    if (this.downloadMode.getSelectedItem()
+        .equals(MapillaryDownloader.MODES[2])) {
       Main.pref.put("mapillary.download-mode", MapillaryDownloader.MODES[2]);
       MapillaryPlugin.setMenuEnabled(MapillaryPlugin.DOWNLOAD_VIEW_MENU, true);
@@ -131,5 +136,5 @@
    *
    */
-  public class OAuthAction extends AbstractAction {
+  public class LoginAction extends AbstractAction {
 
     private static final long serialVersionUID = -3908477563072057344L;
@@ -158,3 +163,22 @@
     }
   }
+
+  /**
+   * Logs the user out.
+   *
+   * @author nokutu
+   *
+   */
+  public class LogoutAction extends AbstractAction {
+
+    private static final long serialVersionUID = 3434780936404707219L;
+
+    @Override
+    public void actionPerformed(ActionEvent arg0) {
+      MapillaryUser.reset();
+      Main.pref.put("mapillary.access-token", null);
+      MapillaryPreferenceSetting.this.login.setText("Login");
+    }
+  }
+
 }
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/MapillaryUser.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/MapillaryUser.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/MapillaryUser.java	(revision 31457)
@@ -2,7 +2,8 @@
 
 import java.io.IOException;
-import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.HashMap;
+
+import org.openstreetmap.josm.Main;
 
 /**
@@ -15,4 +16,6 @@
   private static String images_policy;
   private static String images_hash;
+  /** If the stored token is valid or not. */
+  public static boolean isTokenValid = true;
 
   /**
@@ -20,14 +23,19 @@
    *
    * @return The username of the logged in user.
-   * @throws MalformedURLException
-   * @throws IOException
    */
-  public static String getUsername() throws MalformedURLException, IOException {
+  public static String getUsername() {
+    if (!isTokenValid)
+      return null;
     if (username == null)
-      username = OAuthUtils
-          .getWithHeader(
-              new URL(
-                  "https://a.mapillary.com/v2/me?client_id=T1Fzd20xZjdtR0s1VDk5OFNIOXpYdzoxNDYyOGRkYzUyYTFiMzgz"))
-          .getString("username");
+      try {
+        username = OAuthUtils
+            .getWithHeader(
+                new URL(
+                    "https://a.mapillary.com/v2/me?client_id=T1Fzd20xZjdtR0s1VDk5OFNIOXpYdzoxNDYyOGRkYzUyYTFiMzgz"))
+            .getString("username");
+      } catch (IOException e) {
+        Main.error(e);
+        isTokenValid = false;
+      }
 
     return username;
@@ -37,23 +45,33 @@
    * @return A HashMap object containing the images_policy and images_hash
    *         strings.
-   * @throws MalformedURLException
-   * @throws IOException
    */
-  public static HashMap<String, String> getSecrets()
-      throws MalformedURLException, IOException {
+  public static HashMap<String, String> getSecrets() {
+    if (!isTokenValid)
+      return null;
     HashMap<String, String> hash = new HashMap<>();
     if (images_hash == null)
-      images_hash = OAuthUtils
-          .getWithHeader(
-              new URL(
-                  "https://a.mapillary.com/v2/me/uploads/secrets?client_id=T1Fzd20xZjdtR0s1VDk5OFNIOXpYdzoxNDYyOGRkYzUyYTFiMzgz"))
-          .getString("images_hash");
+      try {
+        images_hash = OAuthUtils
+            .getWithHeader(
+                new URL(
+                    "https://a.mapillary.com/v2/me/uploads/secrets?client_id=T1Fzd20xZjdtR0s1VDk5OFNIOXpYdzoxNDYyOGRkYzUyYTFiMzgz"))
+            .getString("images_hash");
+      } catch (IOException e) {
+        Main.error(e);
+        isTokenValid = false;
+        isTokenValid = false;
+      }
     hash.put("images_hash", images_hash);
     if (images_policy == null)
-      images_policy = OAuthUtils
-          .getWithHeader(
-              new URL(
-                  "https://a.mapillary.com/v2/me/uploads/secrets?client_id=T1Fzd20xZjdtR0s1VDk5OFNIOXpYdzoxNDYyOGRkYzUyYTFiMzgz"))
-          .getString("images_policy");
+      try {
+        images_policy = OAuthUtils
+            .getWithHeader(
+                new URL(
+                    "https://a.mapillary.com/v2/me/uploads/secrets?client_id=T1Fzd20xZjdtR0s1VDk5OFNIOXpYdzoxNDYyOGRkYzUyYTFiMzgz"))
+            .getString("images_policy");
+      } catch (IOException e) {
+        Main.error(e);
+        isTokenValid = false;
+      }
     hash.put("images_policy", images_policy);
     return hash;
@@ -67,4 +85,5 @@
     images_policy = null;
     images_hash = null;
+    isTokenValid = true;
   }
 
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/UploadUtils.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/UploadUtils.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/UploadUtils.java	(revision 31457)
@@ -7,7 +7,4 @@
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
 import java.util.HashMap;
 import java.util.List;
@@ -55,6 +52,8 @@
 public class UploadUtils {
 
+  /** Required keys for POST */
   private static final String[] keys = { "key", "AWSAccessKeyId", "acl",
       "policy", "signature", "Content-Type" };
+  /** Mapillary upload URL */
   private static final String UPLOAD_URL = "https://s3-eu-west-1.amazonaws.com/mapillary.uploads.manual.images";
   /** Count to name temporal files. */
@@ -66,17 +65,8 @@
    * @param image
    *
-   * @throws NoSuchAlgorithmException
-   * @throws UnsupportedEncodingException
-   * @throws InvalidKeyException
-   *
-   */
-  public static void upload(MapillaryImportedImage image)
-      throws InvalidKeyException, UnsupportedEncodingException,
-      NoSuchAlgorithmException {
-    try {
-      upload(image, UUID.randomUUID());
-    } catch (IOException e) {
-      Main.error(e);
-    }
+   */
+  public static void upload(MapillaryImportedImage image) {
+    upload(image, UUID.randomUUID());
+
   }
 
@@ -85,10 +75,6 @@
    * @param uuid
    *          The UUID used to create the sequence.
-   * @throws NoSuchAlgorithmException
-   * @throws InvalidKeyException
-   * @throws IOException
-   */
-  public static void upload(MapillaryImportedImage image, UUID uuid)
-      throws NoSuchAlgorithmException, InvalidKeyException, IOException {
+   */
+  public static void upload(MapillaryImportedImage image, UUID uuid) {
     String key = MapillaryUser.getUsername() + "/" + uuid.toString() + "/"
         + image.getLatLon().lat() + "_" + image.getLatLon().lon() + "_"
@@ -110,8 +96,7 @@
     try {
       uploadFile(updateFile(image), hash);
-    } catch (ImageReadException | ImageWriteException e) {
+    } catch (ImageReadException | ImageWriteException | IOException e) {
       Main.error(e);
     }
-
   }
 
@@ -120,4 +105,6 @@
    * @param hash
    * @throws IOException
+   * @throws IllegalArgumentException
+   *           if the hash doesn't contain all the needed keys.
    */
   public static void uploadFile(File file, HashMap<String, String> hash)
@@ -129,4 +116,6 @@
     MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
     for (String key : keys) {
+      if (hash.get(key) == null)
+        throw new IllegalArgumentException();
       entityBuilder.addPart(key, new StringBody(hash.get(key),
           ContentType.TEXT_PLAIN));
@@ -153,5 +142,5 @@
    */
   public static void uploadSequence(MapillarySequence sequence) {
-    new SequenceUploadThread(sequence.getImages()).start();
+    Main.worker.submit(new SequenceUploadThread(sequence.getImages()));
   }
 
@@ -197,9 +186,6 @@
     @Override
     public void run() {
-      try {
-        upload(this.image, this.uuid);
-      } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
-        Main.error(e);
-      }
+      upload(this.image, this.uuid);
+
     }
   }
@@ -213,6 +199,10 @@
    *         EXIF tags.
    * @throws ImageReadException
+   *           if there are errors reading the image from the file.
    * @throws IOException
+   *           if there are errors getting the metadata from the file or writing
+   *           the output.
    * @throws ImageWriteException
+   *           if there are errors writing the image in the file.
    */
   public static File updateFile(MapillaryImportedImage image)
Index: applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryUtils.java
===================================================================
--- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryUtils.java	(revision 31456)
+++ applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryUtils.java	(revision 31457)
@@ -61,5 +61,4 @@
    *           not one of the values mentioned above
    */
-  // TODO: Maybe move into a separate utility class?
   public static double degMinSecToDouble(RationalNumber[] degMinSec, String ref) {
     if (degMinSec == null || degMinSec.length != 3) {
