95 lines
2.9 KiB
Go
95 lines
2.9 KiB
Go
// Command device is an example Oauth2 Device Authorization Grant app.
|
|
// It creates a new Device Authorization request on the Issuer and then polls for tokens.
|
|
// The user is then prompted to visit a URL and enter the user code.
|
|
// Or, the complete URL can be used instead to omit manual entry.
|
|
// In practice then can be a "magic link" in the form or a QR.
|
|
//
|
|
// The following environment variables are used for configuration:
|
|
//
|
|
// ISSUER: URL to the OP, required.
|
|
// CLIENT_ID: ID of the application, required.
|
|
// CLIENT_SECRET: Secret to authenticate the app using basic auth. Only required if the OP expects this type of authentication.
|
|
// KEY_PATH: Path to a private key file, used to for JWT authentication of the App. Only required if the OP expects this type of authentication.
|
|
// SCOPES: Scopes of the Authentication Request. Optional.
|
|
//
|
|
// Basic usage:
|
|
//
|
|
// cd example/client/device
|
|
// export ISSUER="http://localhost:9000" CLIENT_ID="246048465824634593@demo"
|
|
//
|
|
// Get an Access Token:
|
|
//
|
|
// SCOPES="email profile" go run .
|
|
//
|
|
// Get an Access Token and ID Token:
|
|
//
|
|
// SCOPES="email profile openid" go run .
|
|
//
|
|
// Get an Access Token and Refresh Token
|
|
//
|
|
// SCOPES="email profile offline_access" go run .
|
|
//
|
|
// Get Access, Refresh and ID Tokens:
|
|
//
|
|
// SCOPES="email profile offline_access openid" go run .
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"git.christmann.info/LARA/zitadel-oidc/v3/pkg/client/rp"
|
|
httphelper "git.christmann.info/LARA/zitadel-oidc/v3/pkg/http"
|
|
)
|
|
|
|
var (
|
|
key = []byte("test1234test1234")
|
|
)
|
|
|
|
func main() {
|
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT)
|
|
defer stop()
|
|
|
|
clientID := os.Getenv("CLIENT_ID")
|
|
clientSecret := os.Getenv("CLIENT_SECRET")
|
|
keyPath := os.Getenv("KEY_PATH")
|
|
issuer := os.Getenv("ISSUER")
|
|
scopes := strings.Split(os.Getenv("SCOPES"), " ")
|
|
|
|
cookieHandler := httphelper.NewCookieHandler(key, key, httphelper.WithUnsecure())
|
|
|
|
var options []rp.Option
|
|
if clientSecret == "" {
|
|
options = append(options, rp.WithPKCE(cookieHandler))
|
|
}
|
|
if keyPath != "" {
|
|
options = append(options, rp.WithJWTProfile(rp.SignerFromKeyPath(keyPath)))
|
|
}
|
|
|
|
provider, err := rp.NewRelyingPartyOIDC(ctx, issuer, clientID, clientSecret, "", scopes, options...)
|
|
if err != nil {
|
|
logrus.Fatalf("error creating provider %s", err.Error())
|
|
}
|
|
|
|
logrus.Info("starting device authorization flow")
|
|
resp, err := rp.DeviceAuthorization(ctx, scopes, provider, nil)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
logrus.Info("resp", resp)
|
|
fmt.Printf("\nPlease browse to %s and enter code %s\n", resp.VerificationURI, resp.UserCode)
|
|
|
|
logrus.Info("start polling")
|
|
token, err := rp.DeviceAccessToken(ctx, resp.DeviceCode, time.Duration(resp.Interval)*time.Second, provider)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
logrus.Infof("successfully obtained token: %#v", token)
|
|
}
|