diff --git a/branding/config/vendor.conf b/branding/config/vendor.conf
index 0df2503bb40634449711bd0e401099cfccfdb0bd..a1aca33cd92824373abaf565306b547f82e80d4d 100644
--- a/branding/config/vendor.conf
+++ b/branding/config/vendor.conf
@@ -10,6 +10,7 @@ applicationName     = RiseupVPN
 binaryName          = riseup-vpn
 
 providerURL         = riseup.net
+auth		    = anon
 apiURL              = https://api.black.riseup.net/
 caURL               = https://black.riseup.net/ca.crt
 
@@ -30,6 +31,7 @@ applicationName     = CalyxVPN
 binaryName          = calyx-vpn
 
 providerURL         = https://calyx.net
+auth		    = anon
 apiURL              = https://api.calyx.net:4430/
 caURL               = https://calyx.net/ca.crt
 
@@ -47,6 +49,7 @@ donateURL           = http://example.org
 name                = demo
 applicationName     = DemoVPN
 binaryName          = demo-vpn
+auth		    = anon
 
 providerURL         = pt.demo.bitmask.net
 apiURL              = https://pt.demo.bitmask.net:8000/
diff --git a/branding/scripts/provider.py b/branding/scripts/provider.py
index b1beab9154a05ba432bae4aaca0644251674da07..a88179b7c49bab9b389c414d7ea113ce81eac659 100644
--- a/branding/scripts/provider.py
+++ b/branding/scripts/provider.py
@@ -18,7 +18,7 @@ def getProviderData(provider, config):
     c = config[provider]
     d = dict()
 
-    keys = ('name', 'applicationName', 'binaryName',
+    keys = ('name', 'applicationName', 'binaryName', 'auth',
             'providerURL', 'tosURL', 'helpURL',
             'askForDonations', 'donateURL', 'apiURL',
             'geolocationAPI', 'caCertString')
diff --git a/branding/templates/bitmaskvpn/config.go b/branding/templates/bitmaskvpn/config.go
index a4dc28cb914c64f12c1decabf4777e70fa3cbefb..e3d70cf471e1658ac20d0c1972936ed1ce94c346 100644
--- a/branding/templates/bitmaskvpn/config.go
+++ b/branding/templates/bitmaskvpn/config.go
@@ -10,6 +10,7 @@ const (
 	Provider        = "$providerURL"
 	ApplicationName = "$applicationName"
 	BinaryName      = "$binaryName"
+	Auth            = "$auth"
 	DonateURL       = "$donateURL"
 	AskForDonations = "$askForDonations"
 	HelpURL         = "$helpURL"
diff --git a/pkg/config/config.go b/pkg/config/config.go
index ad159a12e4b89f7bc6daafabb7ed88cb15eb9219..80f5df480cca00934635a9de35a01559382fd81b 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -10,6 +10,7 @@ const (
 	Provider        = "riseup.net"
 	ApplicationName = "RiseupVPN"
 	BinaryName      = "riseup-vpn"
+	Auth            = "anon"
 	DonateURL       = "https://riseup.net/vpn/donate"
 	AskForDonations = "true"
 	HelpURL         = "https://riseup.net/support"
diff --git a/pkg/vpn/bonafide/auth.go b/pkg/vpn/bonafide/auth.go
index b6b3eecd03f92265e87e2ec7f52e8e828fd8692d..62d3d8f92a514985bfa8c46ccd5a77d6c8f5cc67 100644
--- a/pkg/vpn/bonafide/auth.go
+++ b/pkg/vpn/bonafide/auth.go
@@ -15,7 +15,16 @@
 
 package bonafide
 
-type Credentials struct {
+type credentials struct {
 	User     string
 	Password string
 }
+
+// The authentication interface allows to get a Certificate in Pem format.
+// We implement Anonymous Authentication (Riseup et al), and Sip (Libraries).
+
+type authentication interface {
+	needsCredentials() bool
+	getToken(cred *credentials) ([]byte, error)
+	getPemCertificate(cred *credentials) ([]byte, error)
+}
diff --git a/pkg/vpn/bonafide/auth_anon.go b/pkg/vpn/bonafide/auth_anon.go
index 61916e694bfde0ab15f8448eb12b185cbf6915fe..3a666a8fe7387c9776f902dd982606ccc73e7bb3 100644
--- a/pkg/vpn/bonafide/auth_anon.go
+++ b/pkg/vpn/bonafide/auth_anon.go
@@ -16,22 +16,29 @@
 package bonafide
 
 import (
+	"errors"
 	"fmt"
 	"io/ioutil"
 )
 
-type AnonymousAuthentication struct {
-	bonafide *Bonafide
+type anonymousAuthentication struct {
+	client  httpClient
+	authURI string
+	certURI string
 }
 
-func (a *AnonymousAuthentication) GetPemCertificate() ([]byte, error) {
-	resp, err := a.bonafide.client.Post(certAPI, "", nil)
+func (a *anonymousAuthentication) needsCredentials() bool {
+	return true
+}
+
+func (a *anonymousAuthentication) getPemCertificate(cred *credentials) ([]byte, error) {
+	resp, err := a.client.Post(certAPI, "", nil)
 	if err != nil {
 		return nil, err
 	}
 	defer resp.Body.Close()
 	if resp.StatusCode == 404 {
-		resp, err = a.bonafide.client.Post(certAPI3, "", nil)
+		resp, err = a.client.Post(certAPI3, "", nil)
 		if err != nil {
 			return nil, err
 		}
@@ -43,3 +50,7 @@ func (a *AnonymousAuthentication) GetPemCertificate() ([]byte, error) {
 
 	return ioutil.ReadAll(resp.Body)
 }
+
+func (a *anonymousAuthentication) getToken(cred *credentials) ([]byte, error) {
+	return []byte(""), errors.New("anon authentication should not call getToken")
+}
diff --git a/pkg/vpn/bonafide/auth_sip.go b/pkg/vpn/bonafide/auth_sip.go
index 072812f907433e7a011d9686ac16b640b4172f96..b7ab0c8857f8360e790a883121b8bcd98a1885a9 100644
--- a/pkg/vpn/bonafide/auth_sip.go
+++ b/pkg/vpn/bonafide/auth_sip.go
@@ -23,70 +23,67 @@ import (
 	"strings"
 )
 
-type SipAuthentication struct {
-	bonafide *Bonafide
+type sipAuthentication struct {
+	client  httpClient
+	authURI string
+	certURI string
 }
 
-func (a *SipAuthentication) GetPemCertificate() ([]byte, error) {
-	cred := a.bonafide.credentials
+func (a *sipAuthentication) needsCredentials() bool {
+	return true
+}
+
+func (a *sipAuthentication) getPemCertificate(cred *credentials) ([]byte, error) {
 	if cred == nil {
 		return nil, fmt.Errorf("Need bonafide credentials for sip auth")
 	}
-	credJSON, err := formatCredentials(cred.User, cred.Password)
-	if err != nil {
-		return nil, fmt.Errorf("Cannot encode credentials: %s", err)
-	}
-	token, err := a.getToken(credJSON)
+	token, err := a.getToken(cred)
 	if err != nil {
 		return nil, fmt.Errorf("Error while getting token: %s", err)
 	}
-	cert, err := a.getProtectedCert(string(token))
+	cert, err := a.getProtectedCert(a.certURI, string(token))
 	if err != nil {
 		return nil, fmt.Errorf("Error while getting cert: %s", err)
 	}
 	return cert, nil
 }
 
-func (a *SipAuthentication) getProtectedCert(token string) ([]byte, error) {
-	certURL, err := a.bonafide.GetURL("certv3")
+func (a *sipAuthentication) getToken(cred *credentials) ([]byte, error) {
+	/* TODO
+	[ ] get token from disk?
+	[ ] check if expired? set a goroutine to refresh it periodically?
+	*/
+	credJSON, err := formatCredentials(cred.User, cred.Password)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("Cannot encode credentials: %s", err)
 	}
-	req, err := http.NewRequest("POST", certURL, strings.NewReader(""))
-	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
-	resp, err := a.bonafide.client.Do(req)
+	resp, err := http.Post(a.authURI, "text/json", strings.NewReader(credJSON))
 	if err != nil {
-		return nil, fmt.Errorf("Error while getting token: %s", err)
+		return nil, fmt.Errorf("Error on auth request: %v", err)
 	}
 	defer resp.Body.Close()
 	if resp.StatusCode != 200 {
-		return nil, fmt.Errorf("Error %d", resp.StatusCode)
+		return nil, fmt.Errorf("Cannot get token: Error %d", resp.StatusCode)
 	}
 	return ioutil.ReadAll(resp.Body)
 }
 
-func (a *SipAuthentication) getToken(credJson string) ([]byte, error) {
-	/* TODO
-	[ ] get token from disk?
-	[ ] check if expired? set a goroutine to refresh it periodically?
-	*/
-	authURL, err := a.bonafide.GetURL("auth")
-	if err != nil {
-		return nil, fmt.Errorf("Error getting auth url")
-	}
-	resp, err := http.Post(authURL, "text/json", strings.NewReader(credJson))
+func (a *sipAuthentication) getProtectedCert(uri, token string) ([]byte, error) {
+	req, err := http.NewRequest("POST", uri, strings.NewReader(""))
+	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
+	resp, err := a.client.Do(req)
 	if err != nil {
-		return nil, fmt.Errorf("Error on auth request: %v", err)
+		return nil, fmt.Errorf("Error while getting token: %s", err)
 	}
 	defer resp.Body.Close()
 	if resp.StatusCode != 200 {
-		return nil, fmt.Errorf("Cannot get token: Error %d", resp.StatusCode)
+		return nil, fmt.Errorf("Error %d", resp.StatusCode)
 	}
 	return ioutil.ReadAll(resp.Body)
 }
 
 func formatCredentials(user, pass string) (string, error) {
-	c := Credentials{User: user, Password: pass}
+	c := credentials{User: user, Password: pass}
 	credJSON, err := json.Marshal(c)
 	if err != nil {
 		return "", err
diff --git a/pkg/vpn/bonafide/bonafide.go b/pkg/vpn/bonafide/bonafide.go
index 1bc60724c0533f8181dcfe55fa8ade2ea355a1dc..1b48276eb779c6764f616e1f758dd8c569b47a64 100644
--- a/pkg/vpn/bonafide/bonafide.go
+++ b/pkg/vpn/bonafide/bonafide.go
@@ -19,6 +19,7 @@ import (
 	"crypto/tls"
 	"crypto/x509"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -48,8 +49,8 @@ type Bonafide struct {
 	client        httpClient
 	eip           *eipService
 	tzOffsetHours int
-	auth          Authentication
-	credentials   *Credentials
+	auth          authentication
+	credentials   credentials
 	apiURL        string
 }
 
@@ -69,12 +70,6 @@ type httpClient interface {
 	Do(req *http.Request) (*http.Response, error)
 }
 
-// The Authentication interface allows to get a Certificate in Pem format.
-// We implement Anonymous Authentication (Riseup et al), and Sip (Libraries).
-type Authentication interface {
-	GetPemCertificate() ([]byte, error)
-}
-
 type geoLocation struct {
 	IPAddress      string   `json:"ip"`
 	Country        string   `json:"cc"`
@@ -103,44 +98,80 @@ func New() *Bonafide {
 		eip:           nil,
 		tzOffsetHours: tzOffsetHours,
 	}
-	auth := AnonymousAuthentication{b}
-	b.auth = &auth
+	switch auth := config.Auth; auth {
+	case "sip":
+		log.Println("Client expects sip auth")
+		b.auth = &sipAuthentication{client, b.getURL("auth"), b.getURL("certv3")}
+	case "anon":
+		log.Println("Client expects anon auth")
+		b.auth = &anonymousAuthentication{client, "", b.getURL("certv3")}
+	default:
+		log.Println("Client expects invalid auth", auth)
+		b.auth = &anonymousAuthentication{client, "", b.getURL("certv3")}
+	}
+
 	return b
 }
 
-func (b *Bonafide) SetCredentials(username, password string) {
-	b.credentials = &Credentials{username, password}
+func (b *Bonafide) DoLogin(username, password string) (bool, error) {
+	if !b.auth.needsCredentials() {
+		return false, errors.New("Auth method does not need login")
+	}
+
+	cred := credentials{username, password}
+	b.credentials = cred
+
+	/* TODO keep this in memory */
+	_, err := b.auth.getToken(&cred)
+	if err != nil {
+		return false, err
+	}
+
+	return true, nil
 }
 
-func (b *Bonafide) GetURL(object string) (string, error) {
+func (b *Bonafide) checkCredentialsAreSet() bool {
+	if b.credentials.User == "" || b.credentials.Password == "" {
+		log.Println("BUG: expected credentials to be set")
+		return false
+	}
+	return true
+}
+
+func (b *Bonafide) GetPemCertificate() ([]byte, error) {
+	if b.auth == nil {
+		log.Fatal("ERROR: bonafide did not initialize auth")
+	}
+	if b.auth.needsCredentials() {
+		b.checkCredentialsAreSet()
+	}
+
+	cert, err := b.auth.getPemCertificate(&b.credentials)
+	return cert, err
+}
+
+func (b *Bonafide) getURL(object string) string {
 	if b.apiURL == "" {
 		switch object {
 		case "cert":
-			return certAPI, nil
+			return certAPI
 		case "certv3":
-			return certAPI3, nil
+			return certAPI3
 		case "auth":
-			return authAPI, nil
+			return authAPI
 		}
 	} else {
 		switch object {
 		case "cert":
-			return b.apiURL + certPathv1, nil
+			return b.apiURL + certPathv1
 		case "certv3":
-			return b.apiURL + certPathv3, nil
+			return b.apiURL + certPathv3
 		case "auth":
-			return b.apiURL + authPathv3, nil
+			return b.apiURL + authPathv3
 		}
 	}
-	return "", fmt.Errorf("ERROR: unknown object for api url")
-}
-
-func (b *Bonafide) GetPemCertificate() ([]byte, error) {
-	if b.auth == nil {
-		log.Fatal("ERROR: bonafide did not initialize auth")
-	}
-	cert, err := b.auth.GetPemCertificate()
-	return cert, err
+	log.Println("BUG: unknown url object")
+	return ""
 }
 
 func (b *Bonafide) GetGateways(transport string) ([]Gateway, error) {
diff --git a/pkg/vpn/bonafide/eip_service.go b/pkg/vpn/bonafide/eip_service.go
index 148b05224edae8a55da77902a8b0bd21ed629cd4..618eda4dbbcc8ab9228786ac4d8796367ada6e50 100644
--- a/pkg/vpn/bonafide/eip_service.go
+++ b/pkg/vpn/bonafide/eip_service.go
@@ -73,7 +73,7 @@ func (b *Bonafide) setupAuthentication(i interface{}) {
 		case "anon":
 			// Do nothing, we're set on initialization.
 		case "sip":
-			b.auth = &SipAuthentication{b}
+			b.auth = &sipAuthentication{b.client, b.getURL("auth"), b.getURL("certv3")}
 		default:
 			log.Printf("BUG: unknown authentication method %s", auth)
 		}