diff --git a/.gitignore b/.gitignore
index d209a83..2be7de6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
 # See https://help.github.com/ignore-files/ for more about ignoring files.
 
 /api/src/cache/
+/docker-compose.yml
+/photos_path
 
 # dependencies
 node_modules/
diff --git a/api/package-lock.json b/api/package-lock.json
index ae4e4a3..d40c113 100644
--- a/api/package-lock.json
+++ b/api/package-lock.json
@@ -2201,22 +2201,6 @@
       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
       "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
     },
-    "cookie-parser": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz",
-      "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==",
-      "requires": {
-        "cookie": "0.3.1",
-        "cookie-signature": "1.0.6"
-      },
-      "dependencies": {
-        "cookie": {
-          "version": "0.3.1",
-          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
-          "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
-        }
-      }
-    },
     "cookie-signature": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
diff --git a/api/package.json b/api/package.json
index d9c1559..e2112b3 100644
--- a/api/package.json
+++ b/api/package.json
@@ -23,7 +23,6 @@
     "apollo-server": "^2.8.1",
     "babel-runtime": "^6.26.0",
     "body-parser": "^1.19.0",
-    "cookie-parser": "^1.4.4",
     "core-js": "^3.1.4",
     "dotenv": "^8.0.0",
     "exiftool-vendored": "^8.19.0",
diff --git a/api/src/index.js b/api/src/index.js
index ecf0f65..c23a0c2 100644
--- a/api/src/index.js
+++ b/api/src/index.js
@@ -3,7 +3,7 @@ import path from 'path'
 import { ApolloServer } from 'apollo-server-express'
 import express from 'express'
 import bodyParser from 'body-parser'
-import cookieParser from 'cookie-parser'
+import cors from 'cors'
 import { v1 as neo4j } from 'neo4j-driver'
 import { makeAugmentedSchema } from 'neo4j-graphql-js'
 import dotenv from 'dotenv'
@@ -18,7 +18,7 @@ dotenv.config()
 
 const app = express()
 app.use(bodyParser.json())
-app.use(cookieParser())
+app.use(cors())
 
 /*
  * Create an executable GraphQL schema object from GraphQL type definitions
@@ -137,7 +137,7 @@ server.applyMiddleware({ app, graphPath })
 
 import loadImageRoutes from './routes/images'
 
-loadImageRoutes({ app, driver })
+loadImageRoutes({ app, driver, scanner })
 
 const httpServer = http.createServer(app)
 server.installSubscriptionHandlers(httpServer)
diff --git a/api/src/routes/images.js b/api/src/routes/images.js
index a915f02..8c514a1 100644
--- a/api/src/routes/images.js
+++ b/api/src/routes/images.js
@@ -3,21 +3,23 @@ import path from 'path'
 import _ from 'lodash'
 import config from '../config'
 import { isRawImage, getImageCachePath } from '../scanner/utils'
-import { getUserFromToken } from '../token'
+import { getUserFromToken, getTokenFromBearer } from '../token'
 
-function loadImageRoutes({ app, driver }) {
+function loadImageRoutes({ app, driver, scanner }) {
   app.use('/images/:id/:image', async function(req, res) {
     const { id, image } = req.params
 
     let user = null
 
     try {
-      const token = req.cookies.token
+      const token = getTokenFromBearer(req.headers.authorization)
       user = await getUserFromToken(token, driver)
     } catch (err) {
       return res.status(401).send(err.message)
     }
 
+    console.log('Getting image for user', user.username)
+
     const session = driver.session()
 
     const result = await session.run(
diff --git a/ui/Dockerfile b/ui/Dockerfile
index 5dd3568..11b3be8 100644
--- a/ui/Dockerfile
+++ b/ui/Dockerfile
@@ -17,5 +17,6 @@ RUN npm run build
 FROM nginx:stable
 
 COPY --from=0 /app/dist /usr/share/nginx/html
+COPY ./docker-nginx.conf /etc/nginx/conf.d/default.conf
 
 EXPOSE 80
\ No newline at end of file
diff --git a/ui/docker-nginx.conf b/ui/docker-nginx.conf
new file mode 100644
index 0000000..2ff0b30
--- /dev/null
+++ b/ui/docker-nginx.conf
@@ -0,0 +1,9 @@
+server {
+	listen 80 default_server;
+
+	root /usr/share/nginx/html;
+
+	location / {
+		try_files $uri /index.html;
+	}
+}
\ No newline at end of file
diff --git a/ui/package-lock.json b/ui/package-lock.json
index c19c265..9067f6a 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -81,12 +81,6 @@
             "lodash": "^4.17.13",
             "to-fast-properties": "^2.0.0"
           }
-        },
-        "lodash": {
-          "version": "4.17.15",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
-          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
-          "dev": true
         }
       }
     },
@@ -788,6 +782,18 @@
         "@babel/helper-plugin-utils": "^7.0.0"
       }
     },
+    "@babel/plugin-transform-runtime": {
+      "version": "7.5.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.5.5.tgz",
+      "integrity": "sha512-6Xmeidsun5rkwnGfMOp6/z9nSzWpHFNVr2Jx7kwoq4mVatQfQx5S56drBgEHF+XQbKOdIaOiMIINvp/kAwMN+w==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-module-imports": "^7.0.0",
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "resolve": "^1.8.1",
+        "semver": "^5.5.1"
+      }
+    },
     "@babel/plugin-transform-shorthand-properties": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz",
@@ -2131,11 +2137,6 @@
         "safe-buffer": "~5.1.1"
       }
     },
-    "cookie": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
-      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
-    },
     "copy-descriptor": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
diff --git a/ui/package.json b/ui/package.json
index d3a1dad..bbf3414 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -12,7 +12,6 @@
     "apollo-link-http": "^1.5.15",
     "apollo-link-ws": "^1.0.18",
     "babel-plugin-styled-components": "^1.10.6",
-    "cookie": "^0.4.0",
     "graphql": "^14.2.1",
     "graphql-tag": "^2.10.1",
     "parcel-bundler": "^1.12.3",
@@ -38,6 +37,7 @@
   },
   "devDependencies": {
     "@babel/core": "^7.5.5",
+    "@babel/plugin-transform-runtime": "^7.5.5",
     "husky": "^3.0.2",
     "isarray": "^2.0.5",
     "lint-staged": "^9.2.1"
@@ -63,7 +63,8 @@
       ]
     ],
     "plugins": [
-      "babel-plugin-styled-components"
+      "babel-plugin-styled-components",
+      "@babel/plugin-transform-runtime"
     ]
   },
   "lint-staged": {
diff --git a/ui/src/Pages/AllAlbumsPage/AlbumBox.js b/ui/src/Pages/AllAlbumsPage/AlbumBox.js
index 8f6f2ec..ee4b5fb 100644
--- a/ui/src/Pages/AllAlbumsPage/AlbumBox.js
+++ b/ui/src/Pages/AllAlbumsPage/AlbumBox.js
@@ -1,6 +1,8 @@
 import React from 'react'
 import styled from 'styled-components'
 import { Link } from 'react-router-dom'
+import ProtectedImage from '../../components/photoGallery/ProtectedImage'
+import { Icon } from 'semantic-ui-react'
 
 const AlbumBoxLink = styled(Link)`
   width: 240px;
@@ -10,16 +12,30 @@ const AlbumBoxLink = styled(Link)`
   color: #222;
 `
 
-const AlbumBoxImage = styled.div`
-  width: 220px;
-  height: 220px;
-  margin: auto;
-  border-radius: 4%;
-  background-image: url('${props => props.image}');
-  background-color: #eee;
-  background-size: cover;
-  background-position: center;
-`
+const AlbumBoxImage = ({ src, ...props }) => {
+  const Image = styled(ProtectedImage)`
+    width: 220px;
+    height: 220px;
+    margin: auto;
+    border-radius: 4%;
+    object-fit: cover;
+    object-position: center;
+  `
+
+  const Placeholder = styled.div`
+    width: 220px;
+    height: 220px;
+    border-radius: 4%;
+    margin: auto;
+    background: linear-gradient(#f7f7f7 0%, #eee 100%);
+  `
+
+  if (src) {
+    return <Image {...props} src={src} />
+  }
+
+  return <Placeholder />
+}
 
 export const AlbumBox = ({ album, ...props }) => {
   if (!album) {
@@ -33,7 +49,7 @@ export const AlbumBox = ({ album, ...props }) => {
   return (
     <AlbumBoxLink {...props} to={`/album/${album.id}`}>
       <AlbumBoxImage
-        image={
+        src={
           album.photos[0] &&
           album.photos[0].thumbnail &&
           album.photos[0].thumbnail.url
diff --git a/ui/src/Pages/LoginPage/loginUtilFunctions.js b/ui/src/Pages/LoginPage/loginUtilFunctions.js
index 842a8b2..8a11263 100644
--- a/ui/src/Pages/LoginPage/loginUtilFunctions.js
+++ b/ui/src/Pages/LoginPage/loginUtilFunctions.js
@@ -8,15 +8,7 @@ export const checkInitialSetupQuery = gql`
   }
 `
 
-export function setCookie(cname, cvalue, exdays) {
-  var d = new Date()
-  d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000)
-  var expires = 'expires=' + d.toUTCString()
-  document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/'
-}
-
 export function login(token) {
   localStorage.setItem('token', token)
-  setCookie('token', token, 360)
   window.location = '/'
 }
diff --git a/ui/src/components/photoGallery/Photo.js b/ui/src/components/photoGallery/Photo.js
index 5c9e53f..df0f02c 100644
--- a/ui/src/components/photoGallery/Photo.js
+++ b/ui/src/components/photoGallery/Photo.js
@@ -1,8 +1,9 @@
-import React from 'react'
+import React, { useState, useEffect } from 'react'
 import styled from 'styled-components'
 import { useSpring, animated } from 'react-spring'
 import LazyLoad from 'react-lazyload'
 import { Icon } from 'semantic-ui-react'
+import ProtectedImage from './ProtectedImage'
 
 const PhotoContainer = styled.div`
   flex-grow: 1;
@@ -13,7 +14,7 @@ const PhotoContainer = styled.div`
 `
 
 const PhotoImg = photoProps => {
-  const StyledPhoto = styled(animated.img)`
+  const StyledPhoto = styled(animated(ProtectedImage))`
     height: 200px;
     min-width: 100%;
     position: relative;
diff --git a/ui/src/components/photoGallery/PresentView.js b/ui/src/components/photoGallery/PresentView.js
index 1511fe6..bd7893d 100644
--- a/ui/src/components/photoGallery/PresentView.js
+++ b/ui/src/components/photoGallery/PresentView.js
@@ -2,6 +2,7 @@ import React from 'react'
 import styled, { createGlobalStyle } from 'styled-components'
 import { Query } from 'react-apollo'
 import gql from 'graphql-tag'
+import ProtectedImage from './ProtectedImage'
 
 const PresentContainer = styled.div`
   position: fixed;
@@ -34,7 +35,7 @@ const imageQuery = gql`
   }
 `
 
-const PresentImage = styled.img`
+const PresentImage = styled(ProtectedImage)`
   width: 100vw;
   height: 100vh;
   object-fit: contain;
diff --git a/ui/src/components/photoGallery/ProtectedImage.js b/ui/src/components/photoGallery/ProtectedImage.js
new file mode 100644
index 0000000..857d0e5
--- /dev/null
+++ b/ui/src/components/photoGallery/ProtectedImage.js
@@ -0,0 +1,49 @@
+import React, { useState, useEffect } from 'react'
+
+/**
+ * An image that needs a authorization header to load
+ */
+class ProtectedImage extends React.Component {
+  constructor(props) {
+    super(props)
+
+    this.state = {
+      imgSrc: null,
+    }
+
+    this.shouldRefresh = true
+  }
+
+  shouldComponentUpdate(newProps) {
+    if (newProps.src != this.props.src) this.shouldRefresh = true
+
+    return true
+  }
+
+  async fetchImage() {
+    if (this.props.src && this.shouldRefresh) {
+      this.shouldRefresh = false
+
+      let image = await fetch(this.props.src, {
+        headers: {
+          Authorization: `Bearer ${localStorage.getItem('token')}`,
+        },
+      })
+
+      image = await image.blob()
+      const url = URL.createObjectURL(image)
+
+      this.setState({
+        imgSrc: url,
+        loadedSrc: this.props.src,
+      })
+    }
+  }
+
+  render() {
+    this.fetchImage()
+    return <img {...this.props} src={this.state.imgSrc} />
+  }
+}
+
+export default ProtectedImage
diff --git a/ui/src/components/sidebar/PhotoSidebar.js b/ui/src/components/sidebar/PhotoSidebar.js
index cf1761c..24ca528 100644
--- a/ui/src/components/sidebar/PhotoSidebar.js
+++ b/ui/src/components/sidebar/PhotoSidebar.js
@@ -4,6 +4,7 @@ import { Query } from 'react-apollo'
 import gql from 'graphql-tag'
 import { SidebarItem } from './SidebarItem'
 import { Loader } from 'semantic-ui-react'
+import ProtectedImage from '../photoGallery/ProtectedImage'
 
 const photoQuery = gql`
   query sidebarPhoto($id: ID) {
@@ -43,7 +44,7 @@ const RightSidebar = styled.div`
   border-left: 1px solid #eee;
 `
 
-const PreviewImage = styled.img`
+const PreviewImage = styled(ProtectedImage)`
   width: 100%;
   height: 333px;
   object-fit: contain;
