diff --git a/assets/main.css b/assets/main.css
index 14ac617..021e600 100644
--- a/assets/main.css
+++ b/assets/main.css
@@ -385,6 +385,10 @@ section.mi .row input[type=checkbox] {
 	position: absolute;
 }
 
+label.error {
+  color: var(--text-important);
+}
+
 section.estimates .entry {
   padding: 10px 3px;
   border-bottom: 2px solid var(--outline);
diff --git a/components/app.vue b/components/app.vue
index 2a99736..9b8e70d 100644
--- a/components/app.vue
+++ b/components/app.vue
@@ -26,7 +26,11 @@ v-else-if="active == 3"
 @removeFeeTemp="(fee) => fees = fees.filter(f => f.id != fee.id)"
 />
 
-<settings :user="user" v-else-if="active == 4" />
+<settings
+:user="user"
+:token="token"
+@updateAvatar="updateAvatar"
+v-else-if="active == 4" />
 <sign-out :user="user" v-else-if="active == 5" />
 </template>
 
@@ -97,12 +101,36 @@ function getUser() {
 		this.user = result[0]
 		if (this.user.avatar) return
 		
-		fetch("/assets/image/empty-avatar.jpg").then(r => r.blob()).
-		then(b => this.user.avatar = b)
+		return getAvatar(token)
+	}).then(b => {
+	    const validTypes = ['image/jpeg', 'image/png']
+    
+        if (!validTypes.includes(b.type) || b.size <= 1) {
+            fetch("/assets/image/empty-avatar.jpg").
+            then(r => r.blob()).then( a => this.user.avatar = a )
+            return
+        }
+        
+        this.user.avatar = b
 	})
 
 }
 
+function getAvatar(t) {
+    return fetch("/api/user/avatar",
+        {method: 'GET',
+            headers: {
+            "Accept": "application/json",
+            "Authorization": `Bearer ${t || this.token}`,
+            }
+        }).then(r => r.blob())
+}
+
+function updateAvatar() {
+	const token = getCookie("skouter")
+    getAvatar(token).then(b => this.user.avatar = b)
+}
+
 function getFees() {
 	const token = getCookie("skouter")
 	
@@ -181,6 +209,8 @@ export default {
 		getUser,
 		getFees,
 		refreshToken,
+		updateAvatar,
+		getAvatar,
 	},
 	data() {
 		return {
diff --git a/components/settings.vue b/components/settings.vue
index d9eba03..b296cdd 100644
--- a/components/settings.vue
+++ b/components/settings.vue
@@ -6,9 +6,10 @@
 <h3>Avatar</h3>
 <canvas width="200" height="200" ref="canvas"></canvas>
 <input type="file"
-@change="e => changeAvatar(e.target.files[0])"
+@change="e => uploadAvatar(e.target.files[0])"
 />
 <button>Upload</button>
+<label class="error">{{avatarError}}</label>
 </section>
 
 <section class="form inputs">
@@ -56,14 +57,16 @@
 </template>
 
 <script setup>
-import { ref, watch } from "vue"
+import { ref, watch, onMounted } from "vue"
 import Dialog from "./dialog.vue"
 
 let avatar = ref(null)
 let ready = ref(false)
 let avatarChanged = ref(false)
+let avatarError = ref('')
 const canvas = ref(null)
 const props = defineProps(['user', 'token'])
+const emit = defineEmits(['updateAvatar'])
 
 function save() {
 }
@@ -73,25 +76,51 @@ function check() {
 }
 
 function uploadAvatar(blob) {
-
+    changeAvatar(blob)?.then(() => {
+        canvas.value.toBlob(b => {
+            fetch(`/api/user/avatar`,
+		    {method: 'POST',
+		        body: b,
+        		headers: {
+            	"Accept": "application/json",
+            	"Authorization": `Bearer ${props.token}`,
+        		},
+	        }).then(resp => {
+	            if (resp.ok) {emit('updateAvatar')}
+	        })
+        })
+    })
+    
+    
+    canvas.value.toBlob(b => {
+       // uploadAvatar(b)
+    })
+    
+    
 }
 
 function changeAvatar(blob) {
+    const validTypes = ['image/jpeg', 'image/png']
+    
+    if (!validTypes.includes(blob.type)) {
+        avatarError.value = 'Image must be JPEG of PNG format'
+        return
+    }
+    
+    avatarError.value = ''
+    
     avatar.value = blob
-    createImageBitmap(blob,
+    return createImageBitmap(blob,
     {resizeWidth: 200, resizeHeight: 200, resizeQuality: 'medium'}).
     then((img) => {
         avatar.value = img
         canvas.value.getContext("2d").drawImage(img, 0, 0, 200, 200)
-        canvas.value.toBlob(b => {
-            console.log(b)
-        })
     })
 }
 
-
-
 watch(props.user, () => {
+    if (!props.user.avatar) return
     changeAvatar(props.user.avatar)
-})
+}, {immediate: true})
+
 </script>
diff --git a/skouter.go b/skouter.go
index 73a9095..5e6f3e8 100644
--- a/skouter.go
+++ b/skouter.go
@@ -17,6 +17,7 @@ import (
 		"errors"
 		"strings"
 		"math"
+		"io"
 		// pdf "github.com/SebastiaanKlippert/go-wkhtmltopdf"
 		"github.com/golang-jwt/jwt/v4"
 )
@@ -959,6 +960,66 @@ func createUser(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 	json.NewEncoder(w).Encode(user)
 }
 
+func fetchAvatar(db *sql.DB, user int) ( []byte, error ) {
+	var img []byte
+	var query string
+	var err error
+
+	query = `SELECT
+	avatar
+	FROM user WHERE user.id = ?
+	`
+	row := db.QueryRow(query, user)
+	err = row.Scan(&img)
+
+	if err != nil {
+		return img, err
+	}
+
+	return img, nil
+}
+
+
+func insertAvatar(db *sql.DB, user int, img []byte) error {
+	query := `UPDATE user
+	SET avatar = ?
+	WHERE id = ?
+	`
+	_, err := db.Exec(query, img, user)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func setAvatar(w http.ResponseWriter, db *sql.DB, r *http.Request) {
+	var validTypes []string = []string{"image/png", "image/jpeg"}
+	var isValidType bool
+	
+	claims, err := getClaims(r)
+	if err != nil { http.Error(w, "Invalid token.", 422); return }
+	img, err := io.ReadAll(r.Body)
+	if err != nil { http.Error(w, "Invalid file.", 422); return }
+	for _, v := range validTypes {
+		if v == http.DetectContentType(img) { isValidType = true }
+	}
+	if !isValidType { http.Error(w, "Invalid file type.", 422); return }
+
+	err = insertAvatar(db, claims.Id, img)
+	if err != nil { http.Error(w, "Could not insert.", 500); return }
+}
+
+func getAvatar(w http.ResponseWriter, db *sql.DB, r *http.Request) {
+	claims, err := getClaims(r)
+	if err != nil { http.Error(w, "Invalid token.", 422); return }
+	img, err := fetchAvatar(db, claims.Id)
+	if err != nil { http.Error(w, "Could not retrieve.", 500); return }
+	
+	w.Header().Set("Content-Type", http.DetectContentType(img))
+	w.Write(img)
+}
+
 func queryBorrower(db *sql.DB, id int) ( Borrower, error ) {
 	var borrower Borrower
 	var query string
@@ -1602,6 +1663,14 @@ func api(w http.ResponseWriter, r *http.Request) {
 	r.Method == http.MethodDelete &&
 	guard(r, 3):
 		deleteUser(w, db, r)
+	case match(p, "/api/user/avatar", &args) &&
+	r.Method == http.MethodGet &&
+	guard(r, 1):
+		getAvatar(w, db, r)
+	case match(p, "/api/user/avatar", &args) &&
+	r.Method == http.MethodPost &&
+	guard(r, 1):
+		setAvatar(w, db, r)
 	case match(p, "/api/fees", &args) &&
 	r.Method == http.MethodGet &&
 	guard(r, 1):