diff --git a/.gitignore b/.gitignore
index 1ef5d60..3d71d76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@ explorer/node_modules
 explorer/dist
 .idea
 dist/*
-assets/bindata.go
\ No newline at end of file
+assets/bindata.go
+.DS_Store
\ No newline at end of file
diff --git a/commands/server/cli_app.go b/commands/server/cli_app.go
index 60cea0b..74c7265 100644
--- a/commands/server/cli_app.go
+++ b/commands/server/cli_app.go
@@ -102,6 +102,11 @@ func ConfigureServer(l *goapp.Lifecycle, conf *config.ServerConfig) {
 					Manager: app.Get("gonode.manager").(*core.PgNodeManager),
 				},
 				"core.raw": &raw.RawViewHandler{},
+				"media.image": &media.MediaViewHandler{
+					Vault:         app.Get("gonode.vault.fs").(*vault.Vault),
+					MaxWidth:      conf.Media.Image.MaxWidth,
+					AllowedWidths: conf.Media.Image.AllowedWidths,
+				},
 			}
 		})
 
diff --git a/docs/modules/guard.md b/docs/modules/guard.md
index 94fe0da..aae0549 100644
--- a/docs/modules/guard.md
+++ b/docs/modules/guard.md
@@ -2,6 +2,7 @@ Guard
 =====
 
 Introduction
+------------
 
 Guard plugin handle request authentification. The modules comes with a dedicated middleware and request authenticators.
 For now there is only 2 authenticators implemented:
diff --git a/docs/modules/media.md b/docs/modules/media.md
new file mode 100644
index 0000000..b061615
--- /dev/null
+++ b/docs/modules/media.md
@@ -0,0 +1,86 @@
+Media
+=====
+
+Introduction
+------------
+
+Media stores information about a media, for now only image and youtube videos are supported.
+
+Image Type
+----------
+
+The image type provides the current fields:
+ 
+Meta:
+
+ - ``Width``
+ - ``Height``
+ - ``Size``
+ - ``ContentType``
+ - ``Length``
+ - ``Exif``: not used yet
+ - ``Hash``: not used yet
+ - ``SourceStatus``: SourceUrl processing status
+ - ``SourceError``: SourceUrl processing result on error
+
+Data: 
+
+ - ``Reference``: contextual information about the media
+ - ``Name``: image name
+ - ``SourceUrl``: can be used to provided an url to retrieve the media
+ 
+You can retrieve the binary through an api call by adding the ``?raw=1`` into the query string. The prism handler can
+also be used, this entry point will provide crop and resize option.
+
+ - ``http://localhost:2405/prism/bcb537ab-b349-4b3d-87e2-e43e17519af7`` => get the original image 
+ - ``http://localhost:2405/prism/bcb537ab-b349-4b3d-87e2-e43e17519af7?mr=250`` => resize the media with the provided width
+ - ``http://localhost:2405/prism/bcb537ab-b349-4b3d-87e2-e43e17519af7?mf=200,200`` => crop the media using a 200x200 square from
+   the center of the image.
+ - ``http://localhost:2405/prism/bcb537ab-b349-4b3d-87e2-e43e17519af7?mf=200,200,50,50`` => crop the media using a 200x200 square from
+ the 50x50 top left corner.
+ 
+The image resize and crop only works with: ``jpg``, ``png`` and ``jpg`` files.
+ 
+YouTube Type
+------------
+
+The YouTube type provided the following fields:
+
+Meta (from youtube metadata)
+
+ - ``Type``
+ - ``Html``
+ - ``Width``
+ - ``Height``
+ - ``Version``
+ - ``Title``
+ - ``ProviderName`` 
+ - ``AuthorName`` 
+ - ``AuthorUrl`` 
+ - ``ProviderUrl`` 
+ - ``ThumbnailUrl`` 
+ - ``ThumbnailWidth`` 
+ - ``ThumbnailHeight`` 
+
+Data:
+
+ - ``Vid``: The video id
+ - ``Status``: processing status
+ - ``Error``: processing error
+ 
+The downloaded thumbnail will become a media type.
+ 
+Configuration
+-------------
+
+```toml
+[media]
+    [media.image]
+    allowed_widths = [100, 200]
+    max_width = 300
+```
+
+ - ``allowed_widths``: slice of valid widths, if empty all widths are possible
+ - ``max_width``: max allows width, if empty and ``allowed_width`` is empty then all widths are possible.
+ 
+*To avoid any issues, those settings must be set and a cache layer configured*
diff --git a/modules/config/config_server.go b/modules/config/config_server.go
index 39ab5f1..def8ec3 100644
--- a/modules/config/config_server.go
+++ b/modules/config/config_server.go
@@ -50,6 +50,15 @@ type ServerSecurity struct {
 	} `toml:"cors"`
 }
 
+type ServerMediaImage struct {
+	AllowedWidths []uint `toml:"allowed_widths"`
+	MaxWidth      uint   `toml:"max_width"`
+}
+
+type ServerMedia struct {
+	Image *ServerMediaImage `toml:"image"`
+}
+
 type ServerDatabase struct {
 	Name    string `toml:"name"`
 	DSN     string `toml:"dsn"`
@@ -78,6 +87,7 @@ type ServerConfig struct {
 	Security   *ServerSecurity            `toml:"security"`
 	Search     *ServerSearch              `toml:"search"`
 	BinData    *ServerBinData             `toml:"bindata"`
+	Media      *ServerMedia               `toml:"media"`
 }
 
 func NewServerConfig() *ServerConfig {
@@ -93,5 +103,11 @@ func NewServerConfig() *ServerConfig {
 			Assets:   make(map[string]*ServerBinDataAsset, 0),
 			//			Templates: make([]string, 0),
 		},
+		Media: &ServerMedia{
+			Image: &ServerMediaImage{
+				MaxWidth: uint(1024),
+				//				AllowedWidths: make([]uint, 0),
+			},
+		},
 	}
 }
diff --git a/modules/config/config_test.go b/modules/config/config_test.go
index a04c58d..6da93bb 100644
--- a/modules/config/config_test.go
+++ b/modules/config/config_test.go
@@ -72,6 +72,10 @@ key = "ZeSecretKey0oo"
         public = "/explorer"
         private = "github.com/rande/gonode/explorer/dist"
 
+[media]
+    [media.image]
+    allowed_widths = [100, 200]
+    max_width = 300
 `, config)
 
 	assert.NoError(t, err)
@@ -103,6 +107,10 @@ key = "ZeSecretKey0oo"
 	assert.Equal(t, "/var/go", config.BinData.BasePath)
 	assert.Equal(t, []string{"/path/post/templates", "/path/media/templates"}, config.BinData.Templates)
 
+	// test media
+	assert.Equal(t, uint(300), config.Media.Image.MaxWidth)
+	assert.Equal(t, []uint{100, 200}, config.Media.Image.AllowedWidths)
+
 	// debug
 	config.Guard.Jwt.Login.Path = `^\/nodes\/(.*)$`
 
diff --git a/modules/helper/reader.go b/modules/helper/reader.go
new file mode 100644
index 0000000..3e3f79d
--- /dev/null
+++ b/modules/helper/reader.go
@@ -0,0 +1,40 @@
+// Copyright © 2014-2015 Thomas Rabaix <thomas.rabaix@gmail.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package helper
+
+import (
+	"io"
+)
+
+type PartialReader struct {
+	Reader io.ReadCloser
+	Size   int
+	Data   []byte
+	Len    int
+}
+
+func (r *PartialReader) Read(p []byte) (n int, err error) {
+	n, err = r.Reader.Read(p)
+
+	toRead := r.Size - len(r.Data)
+
+	if toRead > 0 {
+		if n < toRead {
+			toRead = n
+		}
+
+		dst := make([]byte, toRead)
+		n := copy(dst, p)
+
+		r.Data = append(r.Data, dst[0:n]...)
+	}
+
+	return
+}
+
+func (r *PartialReader) Close() error {
+	return r.Reader.Close()
+}
diff --git a/modules/helper/reader_test.go b/modules/helper/reader_test.go
new file mode 100644
index 0000000..f666c8b
--- /dev/null
+++ b/modules/helper/reader_test.go
@@ -0,0 +1,59 @@
+// Copyright © 2014-2015 Thomas Rabaix <thomas.rabaix@gmail.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package helper
+
+import (
+	"github.com/stretchr/testify/assert"
+	"io/ioutil"
+	"os"
+	"testing"
+)
+
+func Test_Parial_Reader_Incomplet_Data(t *testing.T) {
+
+	f, _ := ioutil.TempFile(os.TempDir(), "gonode_test")
+	f.Write([]byte("hello world"))
+	f.Seek(0, 0)
+
+	defer f.Close()
+
+	r := PartialReader{
+		Reader: f,
+		Size:   20,
+	}
+
+	data := make([]byte, 50)
+
+	n, err := r.Read(data)
+
+	assert.NoError(t, err)
+	assert.Equal(t, 11, n)
+	assert.Equal(t, []byte("hello world"), data[:n])
+	assert.Equal(t, []byte("hello world"), r.Data)
+}
+
+func Test_Parial_Reader_Complet_Data(t *testing.T) {
+
+	f, _ := ioutil.TempFile(os.TempDir(), "gonode_test")
+	f.Write([]byte("hello world"))
+	f.Seek(0, 0)
+
+	defer f.Close()
+
+	r := PartialReader{
+		Reader: f,
+		Size:   5,
+	}
+
+	data := make([]byte, 50)
+
+	n, err := r.Read(data)
+
+	assert.NoError(t, err)
+	assert.Equal(t, 11, n)
+	assert.Equal(t, []byte("hello world"), data[:n])
+	assert.Equal(t, []byte("hello"), r.Data)
+}
diff --git a/modules/media/media_image.go b/modules/media/media_image.go
index 2445388..4372e70 100644
--- a/modules/media/media_image.go
+++ b/modules/media/media_image.go
@@ -9,8 +9,10 @@ import (
 	"fmt"
 	"github.com/lib/pq"
 	"github.com/rande/gonode/core"
+	"github.com/rande/gonode/modules/helper"
 	"github.com/rande/gonode/modules/vault"
 	"io"
+	"net/http"
 )
 
 type ExifMeta map[string]string
@@ -165,13 +167,18 @@ func (l *ImageDownloadListener) Handle(notification *pq.Notification, m core.Nod
 
 	vaultmeta := core.GetVaultMetadata(node)
 
-	_, err = l.Vault.Put(node.UniqueId(), vaultmeta, resp.Body)
+	r := &helper.PartialReader{
+		Reader: resp.Body,
+		Size:   500,
+	}
+
+	_, err = l.Vault.Put(node.UniqueId(), vaultmeta, r)
 
 	if err != nil {
 		return core.PubSubListenContinue, err
 	}
 
-	meta.ContentType = "application/octet-stream"
+	meta.ContentType = http.DetectContentType(r.Data)
 	meta.SourceStatus = core.ProcessStatusDone
 
 	m.Save(node, false)
diff --git a/modules/media/media_image_view.go b/modules/media/media_image_view.go
new file mode 100644
index 0000000..428aada
--- /dev/null
+++ b/modules/media/media_image_view.go
@@ -0,0 +1,190 @@
+// Copyright © 2014-2015 Thomas Rabaix <thomas.rabaix@gmail.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package media
+
+import (
+	"errors"
+	"github.com/nfnt/resize"
+	"github.com/oliamb/cutter"
+	"github.com/rande/gonode/core"
+	"github.com/rande/gonode/modules/vault"
+	"image"
+	"image/gif"
+	"image/jpeg"
+	"image/png"
+	"io"
+	"io/ioutil"
+	"os"
+	"strconv"
+	"strings"
+)
+
+var (
+	InvalidFitOptionsError = errors.New("Invalid fit options")
+	InvalidWidthRangeError = errors.New("Invalid width range")
+	WidthNotAllowedError   = errors.New("Width is not allowed")
+)
+
+func ContainsSize(size uint, allowed []uint) bool {
+	if len(allowed) == 0 {
+		return true
+	}
+
+	for _, v := range allowed {
+		if v == size {
+			return true
+		}
+	}
+
+	return false
+}
+
+type MediaViewHandler struct {
+	Vault         *vault.Vault
+	AllowedWidths []uint
+	MaxWidth      uint
+}
+
+func (m *MediaViewHandler) Execute(node *core.Node, request *core.ViewRequest, response *core.ViewResponse) error {
+	values := request.HttpRequest.URL.Query()
+
+	meta := node.Meta.(*ImageMeta)
+
+	response.HttpResponse.Header().Set("Content-Type", meta.ContentType)
+
+	for _, format := range []string{"image/jpeg", "image/gif", "image/png"} {
+		if format == meta.ContentType { // only resize supported format
+			if _, ok := values["mr"]; ok { // ask for binary content
+				return m.imageResize(node, request, response)
+			} else if _, ok := values["mf"]; ok {
+				return m.imageFit(node, request, response)
+			}
+		}
+	}
+
+	_, err := m.Vault.Get(node.UniqueId(), response.HttpResponse)
+
+	return err
+}
+
+func (m *MediaViewHandler) imageResize(node *core.Node, request *core.ViewRequest, response *core.ViewResponse) error {
+	width, err := strconv.ParseUint(request.HttpRequest.URL.Query().Get("mr"), 10, 0)
+
+	if err != nil {
+		return err
+	}
+
+	if m.MaxWidth > 0 && uint(width) > m.MaxWidth {
+		return InvalidWidthRangeError
+	}
+
+	if !ContainsSize(uint(width), m.AllowedWidths) {
+		return WidthNotAllowedError
+	}
+
+	imageSrc, err := m.getImage(node)
+
+	if err != nil {
+		return err
+	}
+
+	imageDst := resize.Resize(uint(width), 0, imageSrc, resize.Bicubic)
+
+	return m.encode(imageDst, node, response.HttpResponse)
+}
+
+func (m *MediaViewHandler) imageFit(node *core.Node, request *core.ViewRequest, response *core.ViewResponse) error {
+	options := strings.Split(request.HttpRequest.URL.Query().Get("mf"), ",")
+
+	if len(options) != 2 && len(options) != 4 {
+		return InvalidFitOptionsError
+	}
+
+	width, err := strconv.ParseInt(options[0], 10, 0)
+	if err != nil {
+		return err
+	}
+
+	height, err := strconv.ParseInt(options[1], 10, 0)
+	if err != nil {
+		return err
+	}
+
+	if m.MaxWidth > 0 && uint(width) > m.MaxWidth {
+		return InvalidWidthRangeError
+	}
+
+	if !ContainsSize(uint(width), m.AllowedWidths) {
+		return WidthNotAllowedError
+	}
+
+	var cropCenterX, cropCenterY int64
+	var mode cutter.AnchorMode
+	mode = cutter.Centered
+
+	if len(options) == 4 {
+		cropCenterX, err = strconv.ParseInt(options[2], 10, 0)
+		if err != nil {
+			return err
+		}
+
+		cropCenterY, err = strconv.ParseInt(options[3], 10, 0)
+		if err != nil {
+			return err
+		}
+
+		mode = cutter.TopLeft
+	}
+
+	imageSrc, err := m.getImage(node)
+
+	if err != nil {
+		return InvalidFitOptionsError
+	}
+
+	croppedImg, err := cutter.Crop(imageSrc, cutter.Config{
+		Width:  int(width),
+		Height: int(height),
+		Anchor: image.Point{int(cropCenterX), int(cropCenterY)},
+		Mode:   mode,
+	})
+
+	return m.encode(croppedImg, node, response.HttpResponse)
+}
+
+func (m *MediaViewHandler) getImage(node *core.Node) (image.Image, error) {
+	source, _ := ioutil.TempFile(os.TempDir(), "gonode_image_resize_")
+	defer source.Close()
+
+	m.Vault.Get(node.UniqueId(), source)
+	source.Seek(0, 0)
+
+	meta := node.Meta.(*ImageMeta)
+
+	if meta.ContentType == "image/jpeg" {
+		return jpeg.Decode(source)
+	}
+
+	if meta.ContentType == "image/png" {
+		return png.Decode(source)
+	}
+
+	return gif.Decode(source)
+}
+
+func (m *MediaViewHandler) encode(image image.Image, node *core.Node, w io.Writer) error {
+	meta := node.Meta.(*ImageMeta)
+
+	if meta.ContentType == "image/jpeg" {
+		return jpeg.Encode(w, image, nil)
+	}
+
+	if meta.ContentType == "image/png" {
+		return png.Encode(w, image)
+	}
+
+	return gif.Encode(w, image, nil)
+}
diff --git a/modules/media/media_image_view_test.go b/modules/media/media_image_view_test.go
new file mode 100644
index 0000000..6cc539c
--- /dev/null
+++ b/modules/media/media_image_view_test.go
@@ -0,0 +1,304 @@
+// Copyright © 2014-2015 Thomas Rabaix <thomas.rabaix@gmail.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package media
+
+import (
+	"errors"
+	"github.com/rande/gonode/core"
+	"github.com/rande/gonode/modules/vault"
+	"github.com/stretchr/testify/assert"
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"testing"
+)
+
+func Test_ContainsSize(t *testing.T) {
+	assert.True(t, ContainsSize(200, []uint{}))
+	assert.True(t, ContainsSize(200, []uint{100, 200, 400}))
+
+	assert.False(t, ContainsSize(200, []uint{100, 300}))
+}
+
+func GetDriver() vault.VaultDriver {
+	fv, err := os.Open("../../test/fixtures/photo.jpg.vault")
+
+	core.PanicOnError(err)
+
+	driver := &vault.MockedDriver{}
+	driver.
+		// default string for 111...111 uuid
+		On("GetReader", "eb/60/6938046e0b96477b491c35ab8ce174ce96cfef588c827508a14822e16939.bin.vault").
+		Return(fv, nil)
+
+	f, err := os.Open("../../test/fixtures/photo.jpg")
+	core.PanicOnError(err)
+	driver.
+		// default string for 111...111 uuid
+		On("GetReader", "eb/60/6938046e0b96477b491c35ab8ce174ce96cfef588c827508a14822e16939.bin").
+		Return(f, nil)
+
+	return driver
+}
+
+func Test_MediaViewHandler_NoError_And_NoParam(t *testing.T) {
+	n := core.NewNode()
+	n.Meta = &ImageMeta{
+		ContentType: "image/jpeg",
+	}
+
+	m := &MediaViewHandler{
+		Vault: &vault.Vault{
+			Algo:   "no_op",
+			Driver: GetDriver(),
+		},
+	}
+
+	req, _ := http.NewRequest("GET", "/we-don-t-care", nil)
+
+	request := &core.ViewRequest{
+		HttpRequest: req,
+	}
+
+	res := httptest.NewRecorder()
+	response := &core.ViewResponse{
+		HttpResponse: res,
+	}
+
+	err := m.Execute(n, request, response)
+
+	assert.NoError(t, err)
+	assert.Equal(t, "image/jpeg", res.Header().Get("Content-Type"))
+	assert.True(t, len(res.Body.Bytes()) > 1024)
+}
+
+func Test_MediaViewHandler_VaultError(t *testing.T) {
+	driver := &vault.MockedDriver{}
+	driver.
+		// default string for 111...111 uuid
+		On("GetReader", "eb/60/6938046e0b96477b491c35ab8ce174ce96cfef588c827508a14822e16939.bin.vault").
+		Return(nil, errors.New("error"))
+
+	n := core.NewNode()
+	n.Meta = &ImageMeta{
+		ContentType: "image/jpeg",
+	}
+
+	m := &MediaViewHandler{
+		Vault: &vault.Vault{
+			Algo:   "no_op",
+			Driver: driver,
+		},
+	}
+
+	req, _ := http.NewRequest("GET", "/we-don-t-care", nil)
+
+	request := &core.ViewRequest{
+		HttpRequest: req,
+	}
+
+	res := httptest.NewRecorder()
+	response := &core.ViewResponse{
+		HttpResponse: res,
+	}
+
+	err := m.Execute(n, request, response)
+
+	assert.Error(t, err)
+	assert.Equal(t, "image/jpeg", res.Header().Get("Content-Type"))
+}
+
+func Test_MediaViewHandler_InvalidResize_Width(t *testing.T) {
+	n := core.NewNode()
+	n.Meta = &ImageMeta{
+		ContentType: "image/jpeg",
+	}
+
+	m := &MediaViewHandler{
+		Vault: &vault.Vault{
+			Algo:   "no_op",
+			Driver: GetDriver(),
+		},
+		MaxWidth: 300,
+	}
+
+	req, _ := http.NewRequest("GET", "/we-don-t-care?mr=3000", nil)
+
+	request := &core.ViewRequest{
+		HttpRequest: req,
+	}
+
+	res := httptest.NewRecorder()
+	response := &core.ViewResponse{
+		HttpResponse: res,
+	}
+
+	err := m.Execute(n, request, response)
+
+	assert.Error(t, err)
+	assert.Equal(t, err, InvalidWidthRangeError)
+}
+
+func Test_MediaViewHandler_Invalid_Crop_Width(t *testing.T) {
+	n := core.NewNode()
+	n.Meta = &ImageMeta{
+		ContentType: "image/jpeg",
+	}
+
+	m := &MediaViewHandler{
+		Vault: &vault.Vault{
+			Algo:   "no_op",
+			Driver: GetDriver(),
+		},
+		MaxWidth: 300,
+	}
+
+	req, _ := http.NewRequest("GET", "/we-don-t-care?mf=3000,3000", nil)
+
+	request := &core.ViewRequest{
+		HttpRequest: req,
+	}
+
+	res := httptest.NewRecorder()
+	response := &core.ViewResponse{
+		HttpResponse: res,
+	}
+
+	err := m.Execute(n, request, response)
+
+	assert.Error(t, err)
+	assert.Equal(t, err, InvalidWidthRangeError)
+}
+
+func Test_MediaViewHandler_Invalid_Resize_NotAllowedWidth(t *testing.T) {
+	n := core.NewNode()
+	n.Meta = &ImageMeta{
+		ContentType: "image/jpeg",
+	}
+
+	m := &MediaViewHandler{
+		Vault: &vault.Vault{
+			Algo:   "no_op",
+			Driver: GetDriver(),
+		},
+		MaxWidth:      300,
+		AllowedWidths: []uint{100, 150},
+	}
+
+	req, _ := http.NewRequest("GET", "/we-don-t-care?mr=120", nil)
+
+	request := &core.ViewRequest{
+		HttpRequest: req,
+	}
+
+	res := httptest.NewRecorder()
+	response := &core.ViewResponse{
+		HttpResponse: res,
+	}
+
+	err := m.Execute(n, request, response)
+
+	assert.Error(t, err)
+	assert.Equal(t, err, WidthNotAllowedError)
+}
+
+func Test_MediaViewHandler_Invalid_Crop_NotAllowedWidth(t *testing.T) {
+	n := core.NewNode()
+	n.Meta = &ImageMeta{
+		ContentType: "image/jpeg",
+	}
+
+	m := &MediaViewHandler{
+		Vault: &vault.Vault{
+			Algo:   "no_op",
+			Driver: GetDriver(),
+		},
+		MaxWidth:      300,
+		AllowedWidths: []uint{100, 150},
+	}
+
+	req, _ := http.NewRequest("GET", "/we-don-t-care?mf=120,120", nil)
+
+	request := &core.ViewRequest{
+		HttpRequest: req,
+	}
+
+	res := httptest.NewRecorder()
+	response := &core.ViewResponse{
+		HttpResponse: res,
+	}
+
+	err := m.Execute(n, request, response)
+
+	assert.Error(t, err)
+	assert.Equal(t, err, WidthNotAllowedError)
+}
+
+func Test_MediaViewHandler_Resize(t *testing.T) {
+	n := core.NewNode()
+	n.Meta = &ImageMeta{
+		ContentType: "image/jpeg",
+	}
+
+	m := &MediaViewHandler{
+		Vault: &vault.Vault{
+			Algo:   "no_op",
+			Driver: GetDriver(),
+		},
+		MaxWidth:      300,
+		AllowedWidths: []uint{100, 150},
+	}
+
+	req, _ := http.NewRequest("GET", "/we-don-t-care?mr=150", nil)
+
+	request := &core.ViewRequest{
+		HttpRequest: req,
+	}
+
+	res := httptest.NewRecorder()
+	response := &core.ViewResponse{
+		HttpResponse: res,
+	}
+
+	err := m.Execute(n, request, response)
+
+	assert.NoError(t, err)
+	assert.Equal(t, "image/jpeg", res.Header().Get("Content-Type"))
+	assert.True(t, len(res.Body.Bytes()) > 1024)
+}
+
+func Test_MediaViewHandler_Crop(t *testing.T) {
+	n := core.NewNode()
+	n.Meta = &ImageMeta{
+		ContentType: "image/jpeg",
+	}
+
+	m := &MediaViewHandler{
+		Vault: &vault.Vault{
+			Algo:   "no_op",
+			Driver: GetDriver(),
+		},
+		MaxWidth:      300,
+		AllowedWidths: []uint{100, 150},
+	}
+
+	req, _ := http.NewRequest("GET", "/we-don-t-care?mf=150,150", nil)
+
+	request := &core.ViewRequest{
+		HttpRequest: req,
+	}
+
+	res := httptest.NewRecorder()
+	response := &core.ViewResponse{
+		HttpResponse: res,
+	}
+
+	err := m.Execute(n, request, response)
+
+	assert.NoError(t, err)
+	assert.Equal(t, "image/jpeg", res.Header().Get("Content-Type"))
+	assert.True(t, len(res.Body.Bytes()) > 1024)
+}
diff --git a/modules/vault/vault_cipher.go b/modules/vault/vault_cipher.go
index 7a6351a..f076ee6 100644
--- a/modules/vault/vault_cipher.go
+++ b/modules/vault/vault_cipher.go
@@ -34,7 +34,7 @@ func GetCipher(mode string) (Encrypter, Decrypter) {
 		return NoopEncrypter, NoopDecrypter
 
 	default:
-		panic("Unable to find the cipher")
+		panic("Unable to find the cipher: " + mode)
 	}
 }
 
diff --git a/modules/vault/vault_driver_mock.go b/modules/vault/vault_driver_mock.go
new file mode 100644
index 0000000..bc413d5
--- /dev/null
+++ b/modules/vault/vault_driver_mock.go
@@ -0,0 +1,47 @@
+// Copyright © 2014-2015 Thomas Rabaix <thomas.rabaix@gmail.com>.
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package vault
+
+import (
+	"github.com/stretchr/testify/mock"
+	"io"
+)
+
+type MockedDriver struct {
+	mock.Mock
+}
+
+func (m *MockedDriver) Has(key string) bool {
+	args := m.Mock.Called(key)
+
+	return args.Bool(0)
+}
+
+func (m *MockedDriver) GetReader(key string) (io.ReadCloser, error) {
+	args := m.Mock.Called(key)
+
+	if args.Get(0) == nil {
+		return nil, args.Error(1)
+	}
+
+	return args.Get(0).(io.ReadCloser), args.Error(1)
+}
+
+func (m *MockedDriver) GetWriter(key string) (io.WriteCloser, error) {
+	args := m.Mock.Called(key)
+
+	if args.Get(0) == nil {
+		return nil, args.Error(1)
+	}
+
+	return args.Get(0).(io.WriteCloser), args.Error(1)
+}
+
+func (m *MockedDriver) Remove(key string) error {
+	args := m.Mock.Called(key)
+
+	return args.Error(0)
+}
diff --git a/server.toml.dist b/server.toml.dist
index ab81021..8fac57a 100644
--- a/server.toml.dist
+++ b/server.toml.dist
@@ -41,4 +41,9 @@ templates = [
         [bindata.assets.explorer]
         index = "index.html"
         public = ""
-        private = "github.com/rande/gonode/explorer/dist"
\ No newline at end of file
+        private = "github.com/rande/gonode/explorer/dist"
+
+[media]
+    [media.image]
+    allowed_widths = [100, 250, 500, 1024]
+    max_width = 1024
\ No newline at end of file
diff --git a/test/config_test.toml b/test/config_test.toml
index 87febdd..93448f5 100644
--- a/test/config_test.toml
+++ b/test/config_test.toml
@@ -38,4 +38,9 @@ templates = [
     [bindata.assets]
         [bindata.assets.explorer]
         public = "/explorer"
-        private = "github.com/rande/gonode/explorer/dist"
\ No newline at end of file
+        private = "github.com/rande/gonode/explorer/dist"
+
+[media]
+    [media.image]
+    allowed_widths = [100, 250, 500, 1024]
+    max_width = 1024
\ No newline at end of file
diff --git a/test/config_travis.toml b/test/config_travis.toml
index b88a5bf..2ffbfea 100644
--- a/test/config_travis.toml
+++ b/test/config_travis.toml
@@ -38,4 +38,9 @@ templates = [
     [bindata.assets]
         [bindata.assets.explorer]
         public = "/explorer"
-        private = "github.com/rande/gonode/explorer/dist"
\ No newline at end of file
+        private = "github.com/rande/gonode/explorer/dist"
+
+[media]
+    [media.image]
+    allowed_widths = [100, 250, 500, 1024]
+    max_width = 1024
\ No newline at end of file
diff --git a/test/fixtures/fake.go b/test/fixtures/fake.go
index e280aa5..a89028f 100644
--- a/test/fixtures/fake.go
+++ b/test/fixtures/fake.go
@@ -21,7 +21,9 @@ func GetFakeMediaNode(pos int) *core.Node {
 		Name:      "Go pic",
 		Reference: "0x0",
 	}
-	node.Meta = &media.ImageMeta{}
+	node.Meta = &media.ImageMeta{
+		SourceStatus: core.ProcessStatusInit,
+	}
 
 	return node
 }
@@ -162,5 +164,25 @@ func LoadFixtures(m *core.PgNodeManager, max int) error {
 
 	core.PanicOnError(err)
 
+	// create real image
+	image := core.NewNode()
+
+	image.Type = "media.image"
+	image.Name = "The image for resize"
+	image.Slug = "the-image-for-resize"
+	image.Data = &media.Image{
+		Name:      "Resize.jpg",
+		Reference: "0x0",
+		// from: https://github.com/nfnt/resize
+		SourceUrl: "https://camo.githubusercontent.com/ef6fdc21c7c8e17354524f0982cdb52885335191/687474703a2f2f6e666e742e6769746875622e636f6d2f696d672f494d475f333639345f3732302e6a7067",
+	}
+	image.Meta = &media.ImageMeta{
+		SourceStatus: core.ProcessStatusInit,
+	}
+
+	_, err = m.Save(image, false)
+
+	core.PanicOnError(err)
+
 	return nil
 }
diff --git a/test/fixtures/photo.jpg b/test/fixtures/photo.jpg
new file mode 100755
index 0000000..9b52ba2
Binary files /dev/null and b/test/fixtures/photo.jpg differ
diff --git a/test/fixtures/photo.jpg.vault b/test/fixtures/photo.jpg.vault
new file mode 100644
index 0000000..f04a496
--- /dev/null
+++ b/test/fixtures/photo.jpg.vault
@@ -0,0 +1,6 @@
+{
+  "meta_key": "",
+  "bin_key": "",
+  "algo": "no_op",
+  "hash": ""
+}
\ No newline at end of file
