diff --git a/README.md b/README.md
index 4b734cb7386a3678e0686cfe0f26b6fef07d42a4..a3c817c85b4ba90055bacfb8166d227e63f19c72 100644
--- a/README.md
+++ b/README.md
@@ -152,6 +152,7 @@ Obviously you should setup a role user for running in prodution.
 - `provider` : string. Name of the oauth provider. Valid providers are currently "google", "github" and "gitlab".
 - `oauth_client_id` : string. Oauth Client ID. This can be a secret stored in a [vault](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/oauth_client_id`.
 - `oauth_client_secret` : string. Oauth secret. This can be a secret stored in a [vault](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/oauth_client_secret`.
+- `oauth_callback_url` : string. URL that the Oauth provider will redirect to after user authorisation. The path is hardcoded to `"/auth/callback"` in the source.
 - `provider_opts` : object. Additional options for the provider.
 - `users_whitelist` : array of strings. Optional list of whitelisted usernames. If missing, all users of your current domain/organization are allowed to authenticate against cashierd. For Google auth a user is an email address. For GitHub auth a user is a GitHub username.
 
@@ -209,7 +210,7 @@ The server is configured using a HCL configuration file - [example](example-serv
 
 For the server you need the following:
 - A new ssh private key. Generate one in the usual way using `ssh-keygen -f ssh_ca` - this is your CA signing key. At this time Cashier supports RSA, ECDSA and Ed25519 keys. *Important* This key should be kept safe - *ANY* ssh key signed with this key will be able to access your machines.
-- OAuth (Google, GitHub or Gitlab) credentials. Cashier's callback handler is `/auth/callback` so set the callback URL appropriately when creating the credentials.
+- OAuth (Google or GitHub) credentials. You may also need to set the callback URL when creating these.
 
 ## Using cashier
 Once the server is up and running you'll need to configure your client.  
diff --git a/cmd/cashierd/main.go b/cmd/cashierd/main.go
index b054606853d6c4c59cd44bb3cffec416a47a2452..727777399b96b3faca41854184156983ff420372 100644
--- a/cmd/cashierd/main.go
+++ b/cmd/cashierd/main.go
@@ -182,7 +182,7 @@ func signHandler(a *appContext, w http.ResponseWriter, r *http.Request) (int, er
 func loginHandler(a *appContext, w http.ResponseWriter, r *http.Request) (int, error) {
 	state := newState()
 	a.setAuthStateCookie(w, r, state)
-	a.authsession = a.authprovider.StartSession(state, r)
+	a.authsession = a.authprovider.StartSession(state)
 	http.Redirect(w, r, a.authsession.AuthURL, http.StatusFound)
 	return http.StatusFound, nil
 }
diff --git a/example-server.conf b/example-server.conf
index e4484d1979be89686882e3c1e89d9766ad654b02..e0b3ea550a3f3167ce3d21968cef17753228ce07 100644
--- a/example-server.conf
+++ b/example-server.conf
@@ -23,6 +23,7 @@ auth {
   provider = "google"  # Oauth provider to use
   oauth_client_id = "nnnnnnnnnnnnnnnn.apps.googleusercontent.com"  # Oauth client ID
   oauth_client_secret = "yyyyyyyyyyyyyyyyyyyyyy"  # Oauth client secret
+  oauth_callback_url = "https://sshca.example.com/auth/callback"  # Oauth callback url
   provider_opts {
     domain = "example.com"  # Oauth-provider specific options
   }
diff --git a/server/auth/github/github.go b/server/auth/github/github.go
index c985eed2578e0e0403bee2c90b1537fccac3d1bf..46cf76a97665bad865de69e675824b65d924b4c8 100644
--- a/server/auth/github/github.go
+++ b/server/auth/github/github.go
@@ -40,6 +40,7 @@ func New(c *config.Auth) (*Config, error) {
 		config: &oauth2.Config{
 			ClientID:     c.OauthClientID,
 			ClientSecret: c.OauthClientSecret,
+			RedirectURL:  c.OauthCallbackURL,
 			Endpoint:     github.Endpoint,
 			Scopes: []string{
 				string(githubapi.ScopeUser),
@@ -90,8 +91,7 @@ func (c *Config) Revoke(token *oauth2.Token) error {
 }
 
 // StartSession retrieves an authentication endpoint from Github.
-func (c *Config) StartSession(state string, r *http.Request) *auth.Session {
-	c.config.RedirectURL = auth.Oauth2RedirectURL(r)
+func (c *Config) StartSession(state string) *auth.Session {
 	return &auth.Session{
 		AuthURL: c.config.AuthCodeURL(state),
 	}
diff --git a/server/auth/github/github_test.go b/server/auth/github/github_test.go
index d9d5f00a5b10e5a4a4ebd96225eb7e5d9b298624..8c51f4f8f13021342f6a93eb87e56ea3c5ca2b16 100644
--- a/server/auth/github/github_test.go
+++ b/server/auth/github/github_test.go
@@ -2,7 +2,6 @@ package github
 
 import (
 	"fmt"
-	"net/http"
 	"testing"
 
 	"github.com/nsheridan/cashier/server/config"
@@ -23,11 +22,13 @@ func TestNew(t *testing.T) {
 	p, _ := New(&config.Auth{
 		OauthClientID:     oauthClientID,
 		OauthClientSecret: oauthClientSecret,
+		OauthCallbackURL:  oauthCallbackURL,
 		ProviderOpts:      map[string]string{"organization": organization},
 		UsersWhitelist:    users,
 	})
 	a.Equal(p.config.ClientID, oauthClientID)
 	a.Equal(p.config.ClientSecret, oauthClientSecret)
+	a.Equal(p.config.RedirectURL, oauthCallbackURL)
 	a.Equal(p.organization, organization)
 	a.Equal(p.whitelist, map[string]bool{"user": true})
 }
@@ -36,6 +37,7 @@ func TestWhitelist(t *testing.T) {
 	c := &config.Auth{
 		OauthClientID:     oauthClientID,
 		OauthClientSecret: oauthClientSecret,
+		OauthCallbackURL:  oauthCallbackURL,
 		ProviderOpts:      map[string]string{"organization": ""},
 		UsersWhitelist:    []string{},
 	}
@@ -59,10 +61,7 @@ func TestStartSession(t *testing.T) {
 	a := assert.New(t)
 
 	p, _ := newGithub()
-	r := &http.Request{
-		Host: oauthCallbackURL,
-	}
-	s := p.StartSession("test_state", r)
+	s := p.StartSession("test_state")
 	a.Contains(s.AuthURL, "github.com/login/oauth/authorize")
 	a.Contains(s.AuthURL, "state=test_state")
 	a.Contains(s.AuthURL, fmt.Sprintf("client_id=%s", oauthClientID))
@@ -72,6 +71,7 @@ func newGithub() (*Config, error) {
 	c := &config.Auth{
 		OauthClientID:     oauthClientID,
 		OauthClientSecret: oauthClientSecret,
+		OauthCallbackURL:  oauthCallbackURL,
 		ProviderOpts:      map[string]string{"organization": organization},
 	}
 	return New(c)
diff --git a/server/auth/gitlab/gitlab.go b/server/auth/gitlab/gitlab.go
index 27edafa3109b64267fa6ffbee9fd3cdcde69dda7..f76b2e8d75044265371cd2686d9c0202c57c7558 100644
--- a/server/auth/gitlab/gitlab.go
+++ b/server/auth/gitlab/gitlab.go
@@ -2,7 +2,6 @@ package gitlab
 
 import (
 	"errors"
-	"net/http"
 	"strconv"
 
 	"github.com/nsheridan/cashier/server/auth"
@@ -52,6 +51,7 @@ func New(c *config.Auth) (*Config, error) {
 		config: &oauth2.Config{
 			ClientID:     c.OauthClientID,
 			ClientSecret: c.OauthClientSecret,
+			RedirectURL:  c.OauthCallbackURL,
 			Endpoint: oauth2.Endpoint{
 				AuthURL:  siteURL + "oauth/authorize",
 				TokenURL: siteURL + "oauth/token",
@@ -110,8 +110,7 @@ func (c *Config) Revoke(token *oauth2.Token) error {
 }
 
 // StartSession retrieves an authentication endpoint from Gitlab.
-func (c *Config) StartSession(state string, r *http.Request) *auth.Session {
-	c.config.RedirectURL = auth.Oauth2RedirectURL(r)
+func (c *Config) StartSession(state string) *auth.Session {
 	return &auth.Session{
 		AuthURL: c.config.AuthCodeURL(state),
 	}
diff --git a/server/auth/gitlab/gitlab_test.go b/server/auth/gitlab/gitlab_test.go
index 676cda29ecbe6596e47cc273f749c5ccf671411d..39c2701245372b0775778a20e9afce28ab36706b 100644
--- a/server/auth/gitlab/gitlab_test.go
+++ b/server/auth/gitlab/gitlab_test.go
@@ -2,7 +2,6 @@ package gitlab
 
 import (
 	"fmt"
-	"net/http"
 	"testing"
 
 	"github.com/nsheridan/cashier/server/auth"
@@ -26,6 +25,7 @@ func TestNew(t *testing.T) {
 	g := p.(*Config)
 	a.Equal(g.config.ClientID, oauthClientID)
 	a.Equal(g.config.ClientSecret, oauthClientSecret)
+	a.Equal(g.config.RedirectURL, oauthCallbackURL)
 }
 
 func TestNewBrokenSiteURL(t *testing.T) {
@@ -55,10 +55,7 @@ func TestGoodAllUsers(t *testing.T) {
 	a := assert.New(t)
 
 	p, _ := newGitlab()
-	r := &http.Request{
-		Host: oauthCallbackURL,
-	}
-	s := p.StartSession("test_state", r)
+	s := p.StartSession("test_state")
 	a.Contains(s.AuthURL, "exampleorg/oauth/authorize")
 	a.Contains(s.AuthURL, "state=test_state")
 	a.Contains(s.AuthURL, fmt.Sprintf("client_id=%s", oauthClientID))
@@ -80,10 +77,7 @@ func TestStartSession(t *testing.T) {
 	a := assert.New(t)
 
 	p, _ := newGitlab()
-	r := &http.Request{
-		Host: oauthCallbackURL,
-	}
-	s := p.StartSession("test_state", r)
+	s := p.StartSession("test_state")
 	a.Contains(s.AuthURL, "exampleorg/oauth/authorize")
 	a.Contains(s.AuthURL, "state=test_state")
 	a.Contains(s.AuthURL, fmt.Sprintf("client_id=%s", oauthClientID))
@@ -93,6 +87,7 @@ func newGitlab() (auth.Provider, error) {
 	c := &config.Auth{
 		OauthClientID:     oauthClientID,
 		OauthClientSecret: oauthClientSecret,
+		OauthCallbackURL:  oauthCallbackURL,
 		ProviderOpts: map[string]string{
 			"group":    group,
 			"siteurl":  siteurl,
diff --git a/server/auth/google/google.go b/server/auth/google/google.go
index 305b6f4133de3137038f2548c298e52274231bc9..8c6f53bda128ff0893a2825eff70819e5b9e1f71 100644
--- a/server/auth/google/google.go
+++ b/server/auth/google/google.go
@@ -43,6 +43,7 @@ func New(c *config.Auth) (*Config, error) {
 		config: &oauth2.Config{
 			ClientID:     c.OauthClientID,
 			ClientSecret: c.OauthClientSecret,
+			RedirectURL:  c.OauthCallbackURL,
 			Endpoint:     google.Endpoint,
 			Scopes:       []string{googleapi.UserinfoEmailScope, googleapi.UserinfoProfileScope},
 		},
@@ -100,8 +101,7 @@ func (c *Config) Revoke(token *oauth2.Token) error {
 }
 
 // StartSession retrieves an authentication endpoint from Google.
-func (c *Config) StartSession(state string, r *http.Request) *auth.Session {
-	c.config.RedirectURL = auth.Oauth2RedirectURL(r)
+func (c *Config) StartSession(state string) *auth.Session {
 	return &auth.Session{
 		AuthURL: c.config.AuthCodeURL(state, oauth2.SetAuthURLParam("hd", c.domain)),
 	}
diff --git a/server/auth/google/google_test.go b/server/auth/google/google_test.go
index 4d6191b89dbf0aef3ef4d26f21ed9359be4cfdbe..b3d26334a9224b79612ed3cc915e26ece47eded7 100644
--- a/server/auth/google/google_test.go
+++ b/server/auth/google/google_test.go
@@ -2,7 +2,6 @@ package google
 
 import (
 	"fmt"
-	"net/http"
 	"testing"
 
 	"github.com/nsheridan/cashier/server/config"
@@ -23,6 +22,7 @@ func TestNew(t *testing.T) {
 	a.NoError(err)
 	a.Equal(p.config.ClientID, oauthClientID)
 	a.Equal(p.config.ClientSecret, oauthClientSecret)
+	a.Equal(p.config.RedirectURL, oauthCallbackURL)
 	a.Equal(p.domain, domain)
 	a.Equal(p.whitelist, map[string]bool{"user": true})
 }
@@ -31,6 +31,7 @@ func TestWhitelist(t *testing.T) {
 	c := &config.Auth{
 		OauthClientID:     oauthClientID,
 		OauthClientSecret: oauthClientSecret,
+		OauthCallbackURL:  oauthCallbackURL,
 		ProviderOpts:      map[string]string{"domain": ""},
 		UsersWhitelist:    []string{},
 	}
@@ -55,10 +56,7 @@ func TestStartSession(t *testing.T) {
 
 	p, err := newGoogle()
 	a.NoError(err)
-	r := &http.Request{
-		Host: oauthCallbackURL,
-	}
-	s := p.StartSession("test_state", r)
+	s := p.StartSession("test_state")
 	a.Contains(s.AuthURL, "accounts.google.com/o/oauth2/auth")
 	a.Contains(s.AuthURL, "state=test_state")
 	a.Contains(s.AuthURL, fmt.Sprintf("hd=%s", domain))
@@ -69,6 +67,7 @@ func newGoogle() (*Config, error) {
 	c := &config.Auth{
 		OauthClientID:     oauthClientID,
 		OauthClientSecret: oauthClientSecret,
+		OauthCallbackURL:  oauthCallbackURL,
 		ProviderOpts:      map[string]string{"domain": domain},
 		UsersWhitelist:    users,
 	}
diff --git a/server/auth/provider.go b/server/auth/provider.go
index d4a8e58aef5c84bf645dee56b8fcc1e7415470a6..06dc1c9a0b2111ea9f9bc4e66c1c038cb1013523 100644
--- a/server/auth/provider.go
+++ b/server/auth/provider.go
@@ -1,16 +1,11 @@
 package auth
 
-import (
-	"fmt"
-	"net/http"
-
-	"golang.org/x/oauth2"
-)
+import "golang.org/x/oauth2"
 
 // Provider is an abstraction of different auth methods.
 type Provider interface {
 	Name() string
-	StartSession(string, *http.Request) *Session
+	StartSession(string) *Session
 	Exchange(string) (*oauth2.Token, error)
 	Username(*oauth2.Token) string
 	Valid(*oauth2.Token) bool
@@ -33,12 +28,3 @@ func (s *Session) Authorize(provider Provider, code string) error {
 	s.Token = t
 	return nil
 }
-
-// Oauth2RedirectURL returns an OAuth redirect_uri for this request.
-func Oauth2RedirectURL(r *http.Request) string {
-	protocol := "http"
-	if r.TLS != nil {
-		protocol = "https"
-	}
-	return fmt.Sprintf("%s://%s/auth/callback", protocol, r.Host)
-}
diff --git a/server/auth/provider_test.go b/server/auth/provider_test.go
deleted file mode 100644
index e35dcea954e626e5533679425cee9f68434fa79f..0000000000000000000000000000000000000000
--- a/server/auth/provider_test.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package auth
-
-import (
-	"crypto/tls"
-	"net/http"
-	"testing"
-)
-
-func TestHTTP(t *testing.T) {
-	want := "http://example.com/auth/callback"
-	r := &http.Request{
-		Host: "example.com",
-	}
-	ret := Oauth2RedirectURL(r)
-	if want != ret {
-		t.Errorf("Wanted %s, got %s", want, ret)
-	}
-}
-
-func TestHTTPS(t *testing.T) {
-	want := "https://example.com/auth/callback"
-	r := &http.Request{
-		Host: "example.com",
-		TLS:  &tls.ConnectionState{},
-	}
-	ret := Oauth2RedirectURL(r)
-	if want != ret {
-		t.Errorf("Wanted %s, got %s", want, ret)
-	}
-}
diff --git a/server/auth/testprovider/testprovider.go b/server/auth/testprovider/testprovider.go
index 0bc2397bf4f2044dc71ef5224d13f8f0403154e7..e30b04aaa58e8cae689cb47b6b992ead3ebe02f4 100644
--- a/server/auth/testprovider/testprovider.go
+++ b/server/auth/testprovider/testprovider.go
@@ -1,7 +1,6 @@
 package testprovider
 
 import (
-	"net/http"
 	"time"
 
 	"github.com/nsheridan/cashier/server/auth"
@@ -39,7 +38,7 @@ func (c *Config) Revoke(token *oauth2.Token) error {
 }
 
 // StartSession retrieves an authentication endpoint.
-func (c *Config) StartSession(state string, r *http.Request) *auth.Session {
+func (c *Config) StartSession(state string) *auth.Session {
 	return &auth.Session{
 		AuthURL: "https://www.example.com/auth",
 	}
diff --git a/server/config/config.go b/server/config/config.go
index 794ba8a710bd0300b96fd1a77ea1b7711de659c8..422a135e8d8dd71c35d63f1dc5ad417399484ebd 100644
--- a/server/config/config.go
+++ b/server/config/config.go
@@ -43,6 +43,7 @@ type Server struct {
 type Auth struct {
 	OauthClientID     string            `hcl:"oauth_client_id"`
 	OauthClientSecret string            `hcl:"oauth_client_secret"`
+	OauthCallbackURL  string            `hcl:"oauth_callback_url"`
 	Provider          string            `hcl:"provider"`
 	ProviderOpts      map[string]string `hcl:"provider_opts"`
 	UsersWhitelist    []string          `hcl:"users_whitelist"`
diff --git a/server/config/config_test.go b/server/config/config_test.go
index e247917e5d04f0667304e0dca1aa89f98ec8775b..5536a4e9eae756b0daa8e35da918fd69b8166efe 100644
--- a/server/config/config_test.go
+++ b/server/config/config_test.go
@@ -23,6 +23,7 @@ var (
 		Auth: &Auth{
 			OauthClientID:     "client_id",
 			OauthClientSecret: "secret",
+			OauthCallbackURL:  "https://sshca.example.com/auth/callback",
 			Provider:          "google",
 			ProviderOpts:      map[string]string{"domain": "example.com"},
 			UsersWhitelist:    []string{"a_user"},
diff --git a/server/config/testdata/test.config b/server/config/testdata/test.config
index 6584add405b7c7840f5492912fb976af99cd2c14..96899e725c869f26dca4cba8a6fe6aee18bc6dc4 100644
--- a/server/config/testdata/test.config
+++ b/server/config/testdata/test.config
@@ -19,6 +19,7 @@ auth {
   provider = "google"
   oauth_client_id = "client_id"
   oauth_client_secret = "secret"
+  oauth_callback_url = "https://sshca.example.com/auth/callback"
   provider_opts {
     domain = "example.com"
   }