oauth2: support device flow
Device Authorization Grant following RFC 8628 https://datatracker.ietf.org/doc/html/rfc8628 Tested with GitHub Fixes #418 Fixes golang/go#58126 Co-authored-by: cmP <centimitr@gmail.com> Change-Id: Id588867110c6a5289bf1026da5d7ead88f9c7d14 GitHub-Last-Rev: 9a126d7b534532c7d18fb8d6796ad673b95fc09f GitHub-Pull-Request: golang/oauth2#609 Reviewed-on: https://go-review.googlesource.com/c/oauth2/+/450155 Commit-Queue: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com> Auto-Submit: Bryan Mills <bcmills@google.com> Run-TryBot: Matt Hickford <matt.hickford@gmail.com> Reviewed-by: Bryan Mills <bcmills@google.com> Run-TryBot: Bryan Mills <bcmills@google.com>
This commit is contained in:
97
deviceauth_test.go
Normal file
97
deviceauth_test.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package oauth2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
)
|
||||
|
||||
func TestDeviceAuthResponseMarshalJson(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
response DeviceAuthResponse
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
response: DeviceAuthResponse{},
|
||||
want: `{"device_code":"","user_code":"","verification_uri":""}`,
|
||||
},
|
||||
{
|
||||
name: "soon",
|
||||
response: DeviceAuthResponse{
|
||||
Expiry: time.Now().Add(100*time.Second + 999*time.Millisecond),
|
||||
},
|
||||
want: `{"expires_in":100,"device_code":"","user_code":"","verification_uri":""}`,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
begin := time.Now()
|
||||
gotBytes, err := json.Marshal(tc.response)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Contains(tc.want, "expires_in") && time.Since(begin) > 999*time.Millisecond {
|
||||
t.Skip("test ran too slowly to compare `expires_in`")
|
||||
}
|
||||
got := string(gotBytes)
|
||||
if got != tc.want {
|
||||
t.Errorf("want=%s, got=%s", tc.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceAuthResponseUnmarshalJson(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data string
|
||||
want DeviceAuthResponse
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
data: `{}`,
|
||||
want: DeviceAuthResponse{},
|
||||
},
|
||||
{
|
||||
name: "soon",
|
||||
data: `{"expires_in":100}`,
|
||||
want: DeviceAuthResponse{Expiry: time.Now().UTC().Add(100 * time.Second)},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
begin := time.Now()
|
||||
got := DeviceAuthResponse{}
|
||||
err := json.Unmarshal([]byte(tc.data), &got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !cmp.Equal(got, tc.want, cmpopts.IgnoreUnexported(DeviceAuthResponse{}), cmpopts.EquateApproxTime(time.Second+time.Since(begin))) {
|
||||
t.Errorf("want=%#v, got=%#v", tc.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleConfig_DeviceAuth() {
|
||||
var config Config
|
||||
ctx := context.Background()
|
||||
response, err := config.DeviceAuth(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("please enter code %s at %s\n", response.UserCode, response.VerificationURI)
|
||||
token, err := config.DeviceAccessToken(ctx, response)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(token)
|
||||
}
|
||||
Reference in New Issue
Block a user