Conditional force_ssl

Hello, I have a Phoenix app running in Heroku, that uses force_ssl as explained in the Heroku guides (configuring it on the Rocket.Endpoint for production).

This works fine, but for certain routes that listen for callbacks from other servers, I’d need to disable this SSL forcing. Because these other servers are having trouble handshaking our SSL cert or something.

Is there a way to force_ssl in all the app, except for a few selected routes?

1 Like

It is a plug, so you can always wrap it in a plug to do a conditional check before including it.

Also, this exact question and possible work-arounds were discussed a while ago at: https://github.com/phoenixframework/phoenix/issues/1743 :slight_smile:
Which the dev basically just says the same thing I did above, so that seems the best way to do it.

3 Likes

Thank you, I’ll try this. Not sure how to do that as it’s configured on the Endpoint, but it definitely points me to something :slight_smile:

1 Like

Ah, OK, got it working. I removed the force_ssl option on the Endpoint, and instead plugged it on the browser pipeline in the Router, like this:

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery

    if Mix.env == :prod do
      plug Plug.SSL, rewrite_on: [:x_forwarded_proto]
      plug :put_secure_browser_headers
    end
  end

And then, for the routes where I don’t want to enforce SSL, I have another pipeline where it isn’t enforced.

Easy peasy! Thanks!

5 Likes

Ahh that is a simple way of doing it! Thanks for the documentation on that. :slight_smile:

Yeah, I was confused because I was seeing force_ssl as a config option on the Endpoint, and I forgot that it was a plug.

I’ve updated the example to show how to apply this only on the production environment.

1 Like

If you are using channels and you disabled the global config, you also may want to pass the force_ssl: true option to your socket calls in your endpoint.

3 Likes

Thanks, I’m using channels and would like to force ssl on them too - but I don’t see what you mean, in the endpoint the socket call only accepts path and module, how to pass the force_ssl: true option?

https://hexdocs.pm/phoenix/Phoenix.Endpoint.html#socket/2

I assume you’re talking about this socket call?

defmodule MyApp.Endpoint do
  use Phoenix.Endpoint, otp_app: :my_app

  socket "/socket", MyApp.UserSocket

Sorry, you are right. The option should be given to each transport in your socket, so:

transport :websocket, Phoenix.Transports.WebSocket, force_ssl: true