Skip to content
This repository was archived by the owner on Mar 27, 2025. It is now read-only.

Commit a0549b1

Browse files
authored
Merge pull request #271 from arduino/auth0
Use device authentication with Auth0
2 parents b8e17cb + 009941c commit a0549b1

File tree

4 files changed

+133
-7
lines changed

4 files changed

+133
-7
lines changed

.golangci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ run:
4545
- validate.go
4646

4747
linters:
48-
enable-all: true
48+
enable-all: false
4949
disable:
5050
- prealloc
5151
- dupl

auth/auth.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,87 @@ import (
4444
"github.com/pkg/errors"
4545
)
4646

47+
type DeviceCode struct {
48+
DeviceCode string `json:"device_code"`
49+
UserCode string `json:"user_code"`
50+
VerificationURI string `json:"verification_uri"`
51+
ExpiresIn int `json:"expires_in"`
52+
Interval int `json:"interval"`
53+
VerificationURIComplete string `json:"verification_uri_complete"`
54+
}
55+
56+
func StartDeviceAuth(authURL, clientID string) (data DeviceCode, err error) {
57+
url := authURL + "/oauth/device/code"
58+
59+
payload := strings.NewReader("client_id=" + clientID + "&audience=https://api.arduino.cc")
60+
61+
req, err := http.NewRequest("POST", url, payload)
62+
if err != nil {
63+
return data, err
64+
}
65+
66+
req.Header.Add("content-type", "application/x-www-form-urlencoded")
67+
68+
res, err := http.DefaultClient.Do(req)
69+
if err != nil {
70+
return data, err
71+
}
72+
73+
defer res.Body.Close()
74+
body, err := ioutil.ReadAll(res.Body)
75+
if err != nil {
76+
return data, err
77+
}
78+
79+
err = json.Unmarshal(body, &data)
80+
if err != nil {
81+
return data, err
82+
}
83+
84+
return data, nil
85+
}
86+
87+
func CheckDeviceAuth(authURL, clientID, deviceCode string) (token string, err error) {
88+
url := authURL + "/oauth/token"
89+
90+
payload := strings.NewReader("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=" + deviceCode + "&client_id=" + clientID)
91+
92+
req, err := http.NewRequest("POST", url, payload)
93+
if err != nil {
94+
return token, err
95+
}
96+
97+
req.Header.Add("content-type", "application/x-www-form-urlencoded")
98+
99+
res, err := http.DefaultClient.Do(req)
100+
if err != nil {
101+
return token, err
102+
}
103+
104+
defer res.Body.Close()
105+
body, err := ioutil.ReadAll(res.Body)
106+
if err != nil {
107+
return token, err
108+
}
109+
110+
if res.StatusCode != 200 {
111+
return token, errors.New(string(body))
112+
}
113+
114+
data := struct {
115+
AccessToken string `json:"access_token"`
116+
ExpiresIn int `json:"expires_in"`
117+
TokenType string `json:"token_type"`
118+
}{}
119+
120+
err = json.Unmarshal(body, &data)
121+
if err != nil {
122+
return token, err
123+
}
124+
125+
return data.AccessToken, nil
126+
}
127+
47128
// Config contains the variables you may want to change
48129
type Config struct {
49130
// CodeURL is the endpoint to redirect to obtain a code

install.go

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package main
2020

2121
import (
2222
"bytes"
23+
"context"
2324
"crypto/ecdsa"
2425
"crypto/elliptic"
2526
"crypto/rand"
@@ -40,7 +41,7 @@ import (
4041
"time"
4142

4243
"github.com/arduino/arduino-connector/auth"
43-
"github.com/eclipse/paho.mqtt.golang"
44+
mqtt "github.com/eclipse/paho.mqtt.golang"
4445
"github.com/facchinm/service"
4546
"github.com/kardianos/osext"
4647
"github.com/pkg/errors"
@@ -64,8 +65,8 @@ func register(config Config, configFile, token string) {
6465
// Request token
6566
var err error
6667
if token == "" {
67-
token, err = askCredentials(config.AuthURL)
68-
check(err, "AskCredentials")
68+
token, err = deviceAuth(config.AuthURL, config.AuthClientID)
69+
check(err, "deviceAuth")
6970
}
7071

7172
// Generate a Private Key and CSR
@@ -142,6 +143,40 @@ func registerDeviceViaMQTT(config Config) {
142143

143144
}
144145

146+
// Implements Auth0 device authentication flow: https://auth0.com/docs/flows/guides/device-auth/call-api-device-auth
147+
func deviceAuth(authURL, clientID string) (token string, err error) {
148+
code, err := auth.StartDeviceAuth(authURL, clientID)
149+
if err != nil {
150+
return "", err
151+
}
152+
153+
fmt.Printf("Go to %s and confirm authentication\n", code.VerificationURIComplete)
154+
155+
ticker := time.NewTicker(10 * time.Second)
156+
157+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
158+
159+
// Loop until the user authenticated or the timeout hits
160+
Loop:
161+
for {
162+
select {
163+
case <-ctx.Done():
164+
break Loop
165+
case <-ticker.C:
166+
var err error
167+
token, err = auth.CheckDeviceAuth(authURL, clientID, code.DeviceCode)
168+
if err == nil {
169+
cancel()
170+
}
171+
}
172+
}
173+
174+
ticker.Stop()
175+
cancel()
176+
177+
return token, nil
178+
}
179+
145180
func askCredentials(authURL string) (token string, err error) {
146181
var user, pass string
147182
fmt.Println("Insert your arduino username")

main.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131
"time"
3232

3333
docker "github.com/docker/docker/client"
34-
"github.com/eclipse/paho.mqtt.golang"
34+
mqtt "github.com/eclipse/paho.mqtt.golang"
3535
"github.com/fsnotify/fsnotify"
3636
"github.com/hpcloud/tail"
3737
"github.com/namsral/flag"
@@ -59,6 +59,7 @@ type Config struct {
5959
HTTPSProxy string
6060
ALLProxy string
6161
AuthURL string
62+
AuthClientID string
6263
APIURL string
6364
updateURL string
6465
appName string
@@ -76,6 +77,7 @@ func (c Config) String() string {
7677
out += "https_proxy=" + c.HTTPSProxy + "\r\n"
7778
out += "all_proxy=" + c.ALLProxy + "\r\n"
7879
out += "authurl=" + c.AuthURL + "\r\n"
80+
out += "auth_client_id=" + c.AuthClientID + "\r\n"
7981
out += "apiurl=" + c.APIURL + "\r\n"
8082
out += "cert_path=" + c.CertPath + "\r\n"
8183
out += "sketches_path=" + c.SketchesPath + "\r\n"
@@ -108,7 +110,7 @@ func main() {
108110
flag.StringVar(&config.HTTPProxy, "http_proxy", "", "URL of HTTP proxy to use")
109111
flag.StringVar(&config.HTTPSProxy, "https_proxy", "", "URL of HTTPS proxy to use")
110112
flag.StringVar(&config.ALLProxy, "all_proxy", "", "URL of SOCKS proxy to use")
111-
flag.StringVar(&config.AuthURL, "authurl", "https://hydra.arduino.cc", "Url of authentication server")
113+
flag.StringVar(&config.AuthURL, "authurl", "https://login.arduino.cc", "Url of authentication server")
112114
flag.StringVar(&config.APIURL, "apiurl", "https://api2.arduino.cc", "Url of api server")
113115
flag.BoolVar(&config.CheckRoFs, "check_ro_fs", false, "Check for Read Only file system and remount if necessary")
114116
flag.BoolVar(&debugMqtt, "debug-mqtt", false, "Output all received/sent messages")
@@ -117,6 +119,14 @@ func main() {
117119

118120
flag.Parse()
119121

122+
if config.AuthURL == "https://login.oniudra.cc" {
123+
config.AuthClientID = "ks1R298bA8IQnG4p6dPlbdEIXF6Kt1Lu"
124+
}
125+
126+
if config.AuthURL == "https://login.arduino.cc" {
127+
config.AuthClientID = "QGdLCWFA4uQdbRE2NOFhUI8bnXWMZhCK"
128+
}
129+
120130
if *configFile == "" {
121131
*configFile = defaultConfigFile
122132
}
@@ -128,7 +138,7 @@ func main() {
128138
check(err, "CreateService")
129139

130140
if *doLogin {
131-
token, err := askCredentials(config.AuthURL)
141+
token, err := deviceAuth(config.AuthURL, config.AuthClientID)
132142
if err != nil {
133143
fmt.Fprintln(os.Stderr, err)
134144
os.Exit(1)

0 commit comments

Comments
 (0)