github.com/openshift-online/ocm-sdk-go@v0.1.473/authentication/device_auth.go (about) 1 package authentication 2 3 import ( 4 "context" 5 "fmt" 6 7 "golang.org/x/oauth2" 8 ) 9 10 const ( 11 DeviceAuthURL = "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/auth/device" 12 ) 13 14 type DeviceAuthConfig struct { 15 conf *oauth2.Config 16 verifierOpt oauth2.AuthCodeOption 17 DeviceAuthResponse *oauth2.DeviceAuthResponse 18 ClientID string 19 } 20 21 // Step 1: 22 // Initiates device code flow and returns the device auth config. 23 // After running, use your DeviceAuthConfig to display the user code and verification URI 24 // 25 // fmt.Printf("To continue login, navigate to %v and enter code %v\n", deviceAuthResp.VerificationURI, deviceAuthResp.UserCode) 26 // fmt.Printf("Checking status every %v seconds...\n", deviceAuthResp.Interval) 27 func (d *DeviceAuthConfig) InitiateDeviceAuth(ctx context.Context) (*DeviceAuthConfig, error) { 28 d.conf = &oauth2.Config{ 29 ClientID: d.ClientID, 30 ClientSecret: "", 31 Scopes: []string{"openid"}, 32 Endpoint: oauth2.Endpoint{ 33 DeviceAuthURL: DeviceAuthURL, 34 TokenURL: DefaultTokenURL, 35 }, 36 } 37 38 // Verifiers and Challenges are required for device auth 39 verifier := oauth2.GenerateVerifier() 40 verifierOpt := oauth2.VerifierOption(verifier) 41 challenge := oauth2.S256ChallengeOption(verifier) 42 43 // Get device code 44 deviceAuthResp, err := d.conf.DeviceAuth(ctx, challenge, verifierOpt) 45 if err != nil { 46 return d, fmt.Errorf("failed to get device code: %v", err) 47 } 48 49 d.DeviceAuthResponse = deviceAuthResp 50 d.verifierOpt = verifierOpt 51 52 return d, nil 53 } 54 55 // Step 2: 56 // Initiates polling for token exchange and returns a refresh token 57 func (d *DeviceAuthConfig) PollForTokenExchange(ctx context.Context) (string, error) { 58 if d.DeviceAuthResponse == nil || d.verifierOpt == nil { 59 return "", fmt.Errorf("required config is nil, please run InitiateDeviceAuth first") 60 } 61 // Wait for the user to enter the code, polls at interval specified in deviceAuthResp.Interval 62 token, err := d.conf.DeviceAccessToken(ctx, d.DeviceAuthResponse, d.verifierOpt) 63 if err != nil { 64 return "", fmt.Errorf("error exchanging for token: %v", err) 65 } 66 67 return token.RefreshToken, nil 68 }