Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

* Fix `$AWS_REGION` not set by `eval`/`exec` despite being documented #1277
* Fix bugs parsing AccountId's with leading zero's on the command line #1366
* Default to `AuthWorkflow: device_code` when SSH or WSL sessions are detected #1371

## [v2.2.2] - 2026-05-17

Expand Down
2 changes: 1 addition & 1 deletion cmd/aws-sso/setup_wizard_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func setupWizard(ctx *RunContext, reconfig, addSSO, advanced bool) error {

// check if we are in a ssh session or WSL2
promptedOpen := false
if prompt.IsRemoteHost() || os.Getenv("WSL_DISTRO_NAME") != "" {
if prompt.IsRemoteHost() || prompt.IsWSL() {
// users need to modify the default open action
promptOpen(s)
promptedOpen = true
Expand Down
2 changes: 1 addition & 1 deletion docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ Valid values:
that `aws-sso` is running on the same machine as the browser.** It is not
supported on remote/headless hosts; use `device_code` in those environments.

If `AuthWorkflow` is omitted, `pkce` is used.
If `AuthWorkflow` is omitted, `pkce` is used _unless_ a current SSH/WSL session are detected.

### Accounts

Expand Down
6 changes: 6 additions & 0 deletions internal/prompt/remote_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,9 @@ func IsRemoteHost() bool {
_, inSSHSession := os.LookupEnv("SSH_TTY")
return inSSHSession
}

// IsWSL returns true when running in a WSL environment.
func IsWSL() bool {
_, inWSLSession := os.LookupEnv("WSL_DISTRO_NAME")
return inWSLSession
Comment on lines +35 to +36
}
13 changes: 11 additions & 2 deletions internal/prompt/remote_host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,19 @@ func TestUtilsSuite(t *testing.T) {
s := &UtilsTestSuite{}
suite.Run(t, s)
}

func TestIsRemoteHost(t *testing.T) {
os.Setenv("SSH_TTY", "FOOBAR")
t.Setenv("SSH_TTY", "FOOBAR")
assert.True(t, IsRemoteHost())

os.Unsetenv("SSH_TTY")
assert.NoError(t, os.Unsetenv("SSH_TTY"))
assert.False(t, IsRemoteHost())
}

func TestIsWSL(t *testing.T) {
t.Setenv("WSL_DISTRO_NAME", "Ubuntu")
assert.True(t, IsWSL())

assert.NoError(t, os.Unsetenv("WSL_DISTRO_NAME"))
assert.False(t, IsWSL())
}
12 changes: 10 additions & 2 deletions internal/sso/auth/awssso_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"github.com/aws/aws-sdk-go-v2/aws"
awssso "github.com/aws/aws-sdk-go-v2/service/sso"
"github.com/synfinatic/aws-sso-cli/internal/prompt"
"github.com/synfinatic/aws-sso-cli/internal/sso/oidc"
"github.com/synfinatic/aws-sso-cli/internal/storage"
"github.com/synfinatic/aws-sso-cli/internal/uri"
Expand Down Expand Up @@ -292,9 +293,16 @@ func (as *AWSSSO) saveToken(token storage.CreateTokenResponse) error {
return nil
}

// getAuthWorkflow returns the AuthWorkflow to use for this AWSSSO instance, defaulting
// to PKCE if not set.
// getAuthWorkflow returns the AuthWorkflow to use for this AWSSSO instance.
// In WSL/remote host sessions, we default to device_code when unset; otherwise
// we default to PKCE when unset.
func (as *AWSSSO) getAuthWorkflow() oidc.AuthWorkflow {
if prompt.IsWSL() || prompt.IsRemoteHost() {
if as.SSOConfig == nil || as.SSOConfig.AuthWorkflow == "" {
return oidc.AuthWorkflowDeviceCode
}
}

if as.SSOConfig == nil {
return oidc.AuthWorkflowPKCE
}
Expand Down
34 changes: 34 additions & 0 deletions internal/sso/auth/awssso_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ func TestStoreKey(t *testing.T) {
}

func TestAuthWorkflowSelection(t *testing.T) {
assert.NoError(t, os.Unsetenv("WSL_DISTRO_NAME"))
assert.NoError(t, os.Unsetenv("SSH_TTY"))

as := &AWSSSO{}
assert.Equal(t, as.getAuthWorkflow(), oidc.AuthWorkflowPKCE)
assert.Equal(t, as.authGrantTypes(), []string{string(storage.GrantTypeAuthorizationCode), string(storage.GrantTypeRefreshToken)})
Expand All @@ -114,6 +117,37 @@ func TestAuthWorkflowSelection(t *testing.T) {
assert.Equal(t, as.getAuthWorkflow(), oidc.AuthWorkflowDeviceCode)
assert.Equal(t, as.authGrantTypes(), []string{string(storage.GrantTypeDeviceCode), string(storage.GrantTypeRefreshToken)})
assert.Equal(t, as.GrantTypes(), []storage.GrantType{storage.GrantTypeDeviceCode, storage.GrantTypeRefreshToken})

t.Setenv("WSL_DISTRO_NAME", "Ubuntu")

as = &AWSSSO{}
assert.Equal(t, as.getAuthWorkflow(), oidc.AuthWorkflowDeviceCode)
assert.Equal(t, as.authGrantTypes(), []string{string(storage.GrantTypeDeviceCode), string(storage.GrantTypeRefreshToken)})
assert.Equal(t, as.GrantTypes(), []storage.GrantType{storage.GrantTypeDeviceCode, storage.GrantTypeRefreshToken})

as.SSOConfig = &ssoconfig.SSOConfig{}
assert.Equal(t, as.getAuthWorkflow(), oidc.AuthWorkflowDeviceCode)
assert.Equal(t, as.authGrantTypes(), []string{string(storage.GrantTypeDeviceCode), string(storage.GrantTypeRefreshToken)})
assert.Equal(t, as.GrantTypes(), []storage.GrantType{storage.GrantTypeDeviceCode, storage.GrantTypeRefreshToken})

as.SSOConfig = &ssoconfig.SSOConfig{AuthWorkflow: oidc.AuthWorkflowPKCE}
assert.Equal(t, as.getAuthWorkflow(), oidc.AuthWorkflowPKCE)
assert.Equal(t, as.authGrantTypes(), []string{string(storage.GrantTypeAuthorizationCode), string(storage.GrantTypeRefreshToken)})
assert.Equal(t, as.GrantTypes(), []storage.GrantType{storage.GrantTypeAuthorizationCode, storage.GrantTypeRefreshToken})

assert.NoError(t, os.Unsetenv("WSL_DISTRO_NAME"))
t.Setenv("SSH_TTY", "/dev/pts/1")

as = &AWSSSO{}
assert.Equal(t, as.getAuthWorkflow(), oidc.AuthWorkflowDeviceCode)
assert.Equal(t, as.authGrantTypes(), []string{string(storage.GrantTypeDeviceCode), string(storage.GrantTypeRefreshToken)})
assert.Equal(t, as.GrantTypes(), []storage.GrantType{storage.GrantTypeDeviceCode, storage.GrantTypeRefreshToken})

as.SSOConfig = &ssoconfig.SSOConfig{}
assert.Equal(t, as.getAuthWorkflow(), oidc.AuthWorkflowDeviceCode)

as.SSOConfig = &ssoconfig.SSOConfig{AuthWorkflow: oidc.AuthWorkflowPKCE}
assert.Equal(t, as.getAuthWorkflow(), oidc.AuthWorkflowPKCE)
}

func TestAuthenticateSteps(t *testing.T) {
Expand Down
Loading