diff --git a/pkg/vpn/bonafide/auth.go b/pkg/vpn/bonafide/auth.go
new file mode 100644
index 0000000000000000000000000000000000000000..b6b3eecd03f92265e87e2ec7f52e8e828fd8692d
--- /dev/null
+++ b/pkg/vpn/bonafide/auth.go
@@ -0,0 +1,21 @@
+// Copyright (C) 2018 LEAP
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package bonafide
+
+type Credentials struct {
+	User     string
+	Password string
+}
diff --git a/pkg/vpn/bonafide/auth_anon.go b/pkg/vpn/bonafide/auth_anon.go
new file mode 100644
index 0000000000000000000000000000000000000000..61916e694bfde0ab15f8448eb12b185cbf6915fe
--- /dev/null
+++ b/pkg/vpn/bonafide/auth_anon.go
@@ -0,0 +1,45 @@
+// Copyright (C) 2018-2020 LEAP
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package bonafide
+
+import (
+	"fmt"
+	"io/ioutil"
+)
+
+type AnonymousAuthentication struct {
+	bonafide *Bonafide
+}
+
+func (a *AnonymousAuthentication) GetPemCertificate() ([]byte, error) {
+	resp, err := a.bonafide.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)
+		if err != nil {
+			return nil, err
+		}
+		defer resp.Body.Close()
+	}
+	if resp.StatusCode != 200 {
+		return nil, fmt.Errorf("Get vpn cert has failed with status: %s", resp.Status)
+	}
+
+	return ioutil.ReadAll(resp.Body)
+}
diff --git a/pkg/vpn/bonafide/auth_sip.go b/pkg/vpn/bonafide/auth_sip.go
new file mode 100644
index 0000000000000000000000000000000000000000..d8ebedb924306c6ad3cbce31265b6cc4e0ba6753
--- /dev/null
+++ b/pkg/vpn/bonafide/auth_sip.go
@@ -0,0 +1,88 @@
+// Copyright (C) 2018 LEAP
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package bonafide
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"strings"
+)
+
+type SipAuthentication struct {
+	bonafide *Bonafide
+}
+
+func (a *SipAuthentication) GetPemCertificate() ([]byte, error) {
+	cred := a.bonafide.credentials
+	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)
+	if err != nil {
+		return nil, fmt.Errorf("Error while getting token: %s", err)
+	}
+	cert, err := a.getProtectedCert(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) {
+	req, err := http.NewRequest("POST", certAPI, strings.NewReader(""))
+	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
+	resp, err := a.bonafide.client.Do(req)
+	if err != nil {
+		return nil, fmt.Errorf("Error while getting token: %s", err)
+	}
+	defer resp.Body.Close()
+	if resp.StatusCode != 200 {
+		return nil, fmt.Errorf("Cannot get cert: 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?
+	*/
+	resp, err := http.Post(authAPI, "text/json", strings.NewReader(credJson))
+	if err != nil {
+		log.Fatal("Error on auth request: ", err)
+	}
+	defer resp.Body.Close()
+	if resp.StatusCode != 200 {
+		return nil, fmt.Errorf("Cannot get token: Error %d", resp.StatusCode)
+	}
+	return ioutil.ReadAll(resp.Body)
+}
+
+func formatCredentials(user, pass string) (string, error) {
+	c := Credentials{User: user, Password: pass}
+	credJson, err := json.Marshal(c)
+	if err != nil {
+		return "", err
+	}
+	return string(credJson), nil
+}
diff --git a/pkg/vpn/bonafide/bonafide.go b/pkg/vpn/bonafide/bonafide.go
index fd32f2a8befb15cd68e4f08ad41d6e0929d5cd1a..16a900d4c81ee3d3009b951f085f67971e5ba336 100644
--- a/pkg/vpn/bonafide/bonafide.go
+++ b/pkg/vpn/bonafide/bonafide.go
@@ -32,16 +32,21 @@ import (
 const (
 	certAPI               = config.APIURL + "1/cert"
 	certAPI3              = config.APIURL + "3/cert"
+	authAPI               = config.APIURL + "3/auth"
 	secondsPerHour        = 60 * 60
 	retryFetchJSONSeconds = 15
 )
 
+// Bonafide exposes all the methods needed to communicate with the LEAP server.
 type Bonafide struct {
 	client        httpClient
 	eip           *eipService
 	tzOffsetHours int
+	auth          Authentication
+	credentials   *Credentials
 }
 
+// A Gateway is each one of the remotes we can pass to OpenVPN. It contains a description of all the fields that the eip-service advertises.
 type Gateway struct {
 	Host      string
 	IPAddress string
@@ -55,6 +60,13 @@ type openvpnConfig map[string]interface{}
 
 type httpClient interface {
 	Post(url, contentType string, body io.Reader) (resp *http.Response, err error)
+	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 {
@@ -66,6 +78,7 @@ type geoLocation struct {
 	SortedGateways []string `json:"gateways"`
 }
 
+// New Bonafide: Initializes a Bonafide object. By default, no Credentials are passed.
 func New() *Bonafide {
 	certs := x509.NewCertPool()
 	certs.AppendCertsFromPEM(config.CaCert)
@@ -79,31 +92,23 @@ func New() *Bonafide {
 	_, tzOffsetSeconds := time.Now().Zone()
 	tzOffsetHours := tzOffsetSeconds / secondsPerHour
 
-	return &Bonafide{
+	b := &Bonafide{
 		client:        client,
 		eip:           nil,
 		tzOffsetHours: tzOffsetHours,
 	}
+	auth := AnonymousAuthentication{b}
+	b.auth = &auth
+	return b
 }
 
-func (b *Bonafide) GetCertPem() ([]byte, error) {
-	resp, err := b.client.Post(certAPI, "", nil)
-	if err != nil {
-		return nil, err
-	}
-	defer resp.Body.Close()
-	if resp.StatusCode == 404 {
-		resp, err = b.client.Post(certAPI3, "", nil)
-		if err != nil {
-			return nil, err
-		}
-		defer resp.Body.Close()
-	}
-	if resp.StatusCode != 200 {
-		return nil, fmt.Errorf("get vpn cert has failed with status: %s", resp.Status)
-	}
+func (b *Bonafide) SetCredentials(username, password string) {
+	b.credentials = &Credentials{username, password}
+}
 
-	return ioutil.ReadAll(resp.Body)
+func (b *Bonafide) GetPemCertificate() ([]byte, error) {
+	cert, err := b.auth.GetPemCertificate()
+	return cert, err
 }
 
 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 c097e8a730d07a0bcfb901e262fac1bc9d549759..148b05224edae8a55da77902a8b0bd21ed629cd4 100644
--- a/pkg/vpn/bonafide/eip_service.go
+++ b/pkg/vpn/bonafide/eip_service.go
@@ -23,6 +23,7 @@ type eipService struct {
 	Gateways             []gatewayV3
 	Locations            map[string]location
 	OpenvpnConfiguration openvpnConfig `json:"openvpn_configuration"`
+	auth                 string
 	defaultGateway       string
 }
 
@@ -65,6 +66,22 @@ type transportV3 struct {
 	Options   map[string]string
 }
 
+func (b *Bonafide) setupAuthentication(i interface{}) {
+	switch i.(type) {
+	case eipService:
+		switch auth := b.eip.auth; auth {
+		case "anon":
+			// Do nothing, we're set on initialization.
+		case "sip":
+			b.auth = &SipAuthentication{b}
+		default:
+			log.Printf("BUG: unknown authentication method %s", auth)
+		}
+	case eipServiceV1:
+		// Do nothing, no auth on v1.
+	}
+}
+
 func (b *Bonafide) fetchEipJSON() error {
 	resp, err := b.client.Post(eip3API, "", nil)
 	for err != nil {
@@ -80,24 +97,25 @@ func (b *Bonafide) fetchEipJSON() error {
 	case 404:
 		buf := make([]byte, 128)
 		resp.Body.Read(buf)
-		log.Printf("Error fetching eip v3 json: %s", buf)
+		log.Printf("Error fetching eip v3 json")
 		resp, err = b.client.Post(eip1API, "", nil)
 		if err != nil {
 			return err
 		}
 		defer resp.Body.Close()
 		if resp.StatusCode != 200 {
-			return fmt.Errorf("get eip json has failed with status: %s", resp.Status)
+			return fmt.Errorf("Get eip json has failed with status: %s", resp.Status)
 		}
 
 		b.eip, err = decodeEIP1(resp.Body)
 	default:
-		return fmt.Errorf("get eip json has failed with status: %s", resp.Status)
+		return fmt.Errorf("Get eip json has failed with status: %s", resp.Status)
 	}
 	if err != nil {
 		return err
 	}
 
+	b.setupAuthentication(b.eip)
 	b.sortGateways()
 	return nil
 }
diff --git a/pkg/vpn/bonafide/testdata/eip-service3-sip.json b/pkg/vpn/bonafide/testdata/eip-service3-sip.json
new file mode 100644
index 0000000000000000000000000000000000000000..83f80e5935120e139082797e22eae2f983c326e7
--- /dev/null
+++ b/pkg/vpn/bonafide/testdata/eip-service3-sip.json
@@ -0,0 +1,174 @@
+{
+  "gateways": [
+    {
+      "capabilities": {
+        "adblock": false,
+        "filter_dns": false,
+        "limited": false,
+        "transport": [
+          {
+            "type": "openvpn",
+            "ports": [
+              "443"
+            ],
+            "protocols": [
+              "tcp"
+            ]
+	  },
+          {
+            "type": "obfs4",
+            "ports": [
+              "2345"
+            ],
+            "protocols": [
+              "tcp"
+            ],
+	    "options": {
+              "cert": "obfs-cert",
+              "iat-mode": "0"
+	    }
+	  }
+        ],
+        "user_ips": false
+      },
+      "host": "1.example.com",
+      "ip_address": "1.1.1.1",
+      "location": "a"
+    },
+    {
+      "capabilities": {
+        "adblock": false,
+        "filter_dns": false,
+        "limited": false,
+        "transport": [
+          {
+            "type": "openvpn",
+            "ports": [
+              "443"
+            ],
+            "protocols": [
+              "tcp"
+            ]
+	  }
+        ],
+        "user_ips": false
+      },
+      "host": "2.example.com",
+      "ip_address": "2.2.2.2",
+      "location": "b"
+    },
+    {
+      "capabilities": {
+        "adblock": false,
+        "filter_dns": false,
+        "limited": false,
+        "transport": [
+          {
+            "type": "openvpn",
+            "ports": [
+              "443"
+            ],
+            "protocols": [
+              "tcp"
+            ]
+	  },
+          {
+            "type": "obfs4",
+            "ports": [
+              "2345"
+            ],
+            "protocols": [
+              "tcp"
+            ],
+	    "options": {
+              "cert": "obfs-cert",
+              "iat-mode": "0"
+	    }
+	  }
+        ],
+        "user_ips": false
+      },
+      "host": "3.example.com",
+      "ip_address": "3.3.3.3",
+      "location": "b"
+    },
+    {
+      "capabilities": {
+        "adblock": false,
+        "filter_dns": false,
+        "limited": false,
+        "transport": [
+          {
+            "type": "openvpn",
+            "ports": [
+              "443"
+            ],
+            "protocols": [
+              "tcp"
+            ]
+	  }
+        ],
+        "user_ips": false
+      },
+      "host": "4.example.com",
+      "ip_address": "4.4.4.4",
+      "location": "c"
+    },
+    {
+      "capabilities": {
+        "adblock": false,
+        "filter_dns": false,
+        "limited": false,
+        "transport": [
+          {
+            "type": "obfs4",
+            "ports": [
+              "2345"
+            ],
+            "protocols": [
+              "tcp"
+            ],
+	    "options": {
+              "cert": "obfs-cert",
+              "iat-mode": "0"
+	    }
+	  }
+        ],
+        "user_ips": false
+      },
+      "host": "5.example.com",
+      "ip_address": "5.5.5.5",
+      "location": "c"
+    }
+  ],
+  "locations": {
+    "a": {
+      "country_code": "AA",
+      "hemisphere": "N",
+      "name": "a",
+      "timezone": "-5"
+    },
+    "b": {
+      "country_code": "BB",
+      "hemisphere": "S",
+      "name": "b",
+      "timezone": "+1"
+    },
+    "c": {
+      "country_code": "CC",
+      "hemisphere": "N",
+      "name": "c",
+      "timezone": "+8"
+    }
+  },
+  "openvpn_configuration": {
+    "auth": "SHA1",
+    "cipher": "AES-128-CBC",
+    "keepalive": "10 30",
+    "tls-cipher": "DHE-RSA-AES128-SHA",
+    "tun-ipv6": true
+  },
+  "auth": "sip",
+  "serial": 1,
+  "version": 3
+}