---
title: Download Endpoint
---

The [`download_endpoint`][download_endpoint] plugin provides a Rack app for
downloading uploaded files from specified storages. This can be useful when
files from your storage isn't accessible over URL (e.g. database storages) or
if you want to authenticate your downloads.

## Global Endpoint

You can configure the plugin with the path prefix which the endpoint will be
mounted on.

```rb
Shrine.plugin :download_endpoint, prefix: "attachments"
```

The plugin adds a `Shrine.download_endpoint` method which returns a Rack
application that handles downloads using the `rack_response` plugin. You can
run this Rack app inside your app on the prefix that you specified:

```rb
# config/routes.rb (Rails)
Rails.application.routes.draw do
  # ...
  mount Shrine.download_endpoint => "/attachments"
end
```

Links to the download endpoint are generated by calling
`UploadedFile#download_url` instead of the usual `UploadedFile#url`.

```rb
uploaded_file.download_url #=> "/attachments/eyJpZCI6ImFkdzlyeTM..."
```

## Endpoint via Uploader

You can also configure the plugin in the uploader directly - just make sure to mount it via your Uploader-class.

```rb
class ImageUploader  < Shrine
  plugin :download_endpoint, prefix: "images"
end
```

```rb
# config/routes.rb (Rails)
Rails.application.routes.draw do
  # ...
  mount ImageUploader.download_endpoint => "/images"
end
```

_Hint: For shrine versions 2.x -> ensure that you don't include the plugin
twice (globally and in your uploader class - see #408)_

## Calling from a controller

If you want to run additional code around the download (such as authentication),
mounting the download endpoint in your router might be limiting. You can instead
create a custom controller action and handle download requests there using
`Shrine.download_response`:

```rb
# config/routes.rb (Rails)
Rails.application.routes.draw do
  # ...
  get "/attachments/*rest", to: "downloads#image"
end
```

```rb
# app/controllers/downloads_controller.rb (Rails)
class DownloadsController < ApplicationController
  def image
    # ... we can perform authentication here ...
    set_rack_response ImageUploader.download_response(request.env)
  end

  private

  def set_rack_response((status, headers, body))
    self.status = status
    self.headers.merge!(headers)
    self.response_body = body
  end
end
```

If you want to create an endpoint with a custom path, you can use the
[`rack_response`][rack_response] plugin directly, which this plugin uses
internally.

## Host

You can specify download URL host via the `:host` plugin option:

```rb
plugin :download_endpoint, host: "http://example.com"
```

or by passing `:host` to `UploadedFile#download_url`:

```rb
uploaded_file.download_url(host: "http://example.com")
#=> "http//example.com/attachments/eyJpZCI6ImFkdzlyeTM..."
```

## Download options

If you want to pass additional options to `Storage#open`, you can do so via
`:download_options`:

```rb
plugin :download_endpoint, download_options: {
  sse_customer_algorithm: "AES256",
  sse_customer_key:       "secret_key",
  sse_customer_key_md5:   "secret_key_md5",
}
```

You can also specify a proc to generate download options dynamically:

```rb
plugin :download_endpoint, download_options: -> (uploaded_file, request) {
  {
    sse_customer_algorithm: "AES256",
    sse_customer_key:       "secret_key",
    sse_customer_key_md5:   "secret_key_md5",
  }
}
```

## Expiring download urls

If you want to have URLs that expire after a certain time, you can use the `:expires_in` and `secret_key` options:

```rb
plugin :download_endpoint, expires_in: 5 * 60, secret_key: "secret"
```

this will generate URLs that are signed with a signature valid for 5 minutes.

## Performance considerations

Streaming files through the app might impact the request throughput, depending
on the web server you're using. So it's recommended to use a CDN, which can be
set via the `:host` option.

Alternatively, you can have the endpoint redirect to the direct file URL:

```rb
plugin :download_endpoint, redirect: true
```

You can also specify a proc to generate your own redirect URL:

```rb
plugin :download_endpoint, redirect: -> (uploaded_file, request) do
  uploaded_file.url(public: true)
end
```

## Ad-hoc options

You can override any of the options above when creating the endpoint:

```rb
Shrine.download_endpoint(disposition: "attachment")
```

## Plugin options

| Name                | Description                                                                       | Default  |
| :------------------ | :-------------------------------------------------------------------------------- | :------- |
| `:disposition`      | Whether browser should render the file `inline` or download it as an `attachment` | `inline` |
| `:download_options` | Hash of storage-specific options passed to `Storage#open`                         | `{}`     |
| `:host`             | URL host that will be added to download URLs                                      | `nil`    |
| `:prefix`           | Path prefix prepended to download URLs                                            | `nil`    |
| `:redirect`         | Whether to redirect to uploaded files on the storage                              | `false`  |

[download_endpoint]: https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/download_endpoint.rb
[rack_response]: https://shrinerb.com/docs/plugins/rack_response
