Skip to content

Commit

Permalink
Fix refresh automation
Browse files Browse the repository at this point in the history
  • Loading branch information
MariusStorhaug committed Sep 20, 2023
1 parent 57851e2 commit 6fd7e21
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 55 deletions.
5 changes: 5 additions & 0 deletions .dev/localImport.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ $modulePath = Join-Path $repoPath 'src' 'GitHub'

$PSModulePath += ";$modulePath"
Import-Module "$modulePath"

#####
Get-Module -Name GitHub -ListAvailable | Remove-Module -Force
Get-Module -Name GitHub -ListAvailable | Uninstall-Module -Force -AllVersions
Get-SecretVault | Unregister-SecretVault
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function Get-GitHubDeviceFlowClientID {
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[ValidateSet('OAuthApp', 'GitHubApp')]
[string] $Mode = 'OAuthApp'
)
switch ($Mode) {
'OAuthApp' { $script:GitHubOAuthAppClientID }
'GitHubApp' { $script:GitHubAppClientID }
}
}

1 change: 1 addition & 0 deletions src/GitHub/private/common.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ $script:APIBaseURI = 'https://api.github.com'
$script:ContentType = 'application/vnd.github+json'
$Script:Version = '2022-11-28'
$script:AccessToken = ''
$script:RefreshToken = ''
$script:Owner = ''
$script:Repo = ''
64 changes: 40 additions & 24 deletions src/GitHub/public/Auth/Connect-GitHubAccount.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,29 @@
.NOTES
https://docs.github.com/en/rest/overview/other-authentication-methods#authenticating-for-saml-sso
#>
[CmdletBinding()]
[CmdletBinding(DefaultParameterSetName = 'DeviceFlow')]
param (
# The personal access token to use for authentication.
[Parameter()]
[String] $Token,

# Choose between authentication methods, either OAuthApp or GitHubApp.
# For more info about the types of authentication visit:
# https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/differences-between-github-apps-and-oauth-apps
[Parameter()]
[ValidateSet('OAuthApp', 'GitHubApp', 'PAT')]
[Parameter(ParameterSetName = 'DeviceFlow')]
[ValidateSet('OAuthApp', 'GitHubApp')]
[string] $Mode = 'GitHubApp',

# The scope of the access token, when using OAuth authentication.
# Provide the list of scopes as space-separated values.
# For more information on scopes visit:
# https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps
[Parameter()]
[string] $Scope = 'gist read:org repo workflow'
[Parameter(ParameterSetName = 'DeviceFlow')]
[string] $Scope = 'gist read:org repo workflow',

# Refresh the access token.
[Parameter(ParameterSetName = 'Refresh')]
[switch] $Refresh,

# The personal access token to use for authentication.
[Parameter(ParameterSetName = 'PAT')]
[String] $Token
)

$vault = Get-SecretVault | Where-Object -Property ModuleName -EQ 'Microsoft.PowerShell.SecretStore'
Expand All @@ -58,30 +62,42 @@
$vault = Get-SecretVault | Where-Object -Property ModuleName -EQ 'Microsoft.PowerShell.SecretStore'
}

if ($PSBoundParameters.ContainsKey('Token')) {
$script:AccessToken = $Token
$script:AuthMode = 'PAT'
} else {
$tokenResponse = Invoke-GitHubDeviceCodeLogin -Mode $Mode -Scope $Scope
$accessToken = $tokenResponse.access_token # ghu_#### OR gho_####
$accessTokenExpiresIn = $tokenResponse.expires_in # 28800 = 8 hours
$accessTokenExpirationDate = (Get-Date).AddSeconds($accessTokenExpiresIn) # 2021-09-28T21:00:00.0000000-04:00
$refreshToken = $tokenResponse.refresh_token # ghr_########
$refreshTokenExpiresIn = $tokenResponse.refresh_token_expires_in # 15724800 = 6 months
$refreshTokenExpirationDate = (Get-Date).AddSeconds($refreshTokenExpiresIn) # 2022-03-28T21:00:00.0000000-04:00
#Get the parameter set that is used
switch ($PSCmdlet.ParameterSetName) {
'Refresh' {
$tokenResponse = Invoke-GitHubDeviceFlowLogin -Refresh -Mode $script:AuthMode
}
'DeviceFlow' {
$tokenResponse = Invoke-GitHubDeviceFlowLogin -Mode $Mode -Scope $Scope
}
'PAT' {
$script:AccessToken = $Token
Set-Secret -Name 'GitHubPS.AccessToken' -Secret $script:AccessToken -Vault $vault.Name
Remove-Secret -Name 'GitHubPS.AccessToken.ExpirationDate'-Vault $vault.Name -ErrorAction SilentlyContinue
Remove-Secret -Name 'GitHubPS.RefreshToken'-Vault $vault.Name -ErrorAction SilentlyContinue
Remove-Secret -Name 'GitHubPS.RefreshToken.ExpirationDate'-Vault $vault.Name -ErrorAction SilentlyContinue
Remove-Secret -Name 'GitHubPS.Scope' -Vault $vault.Name -ErrorAction SilentlyContinue
$script:AuthMode = 'PAT'
Set-Secret -Name 'GitHubPS.AuthMode' -Secret $script:AuthMode -Vault $vault.Name
}
}

if ($tokenResponse) {
$script:AccessToken = $tokenResponse.access_token
$accessTokenExpirationDate = (Get-Date).AddSeconds($tokenResponse.expires_in)
$refreshToken = $tokenResponse.refresh_token
$refreshTokenExpirationDate = (Get-Date).AddSeconds($tokenResponse.refresh_token_expires_in)
$tokenScope = $tokenResponse.scope

$script:AccessToken = $accessToken
$script:AuthMode = $Mode
Set-Secret -Name 'GitHubPS.AccessToken' -Secret $accessToken -Vault $vault.Name
Set-Secret -Name 'GitHubPS.AccessToken' -Secret $script:AccessToken -Vault $vault.Name
Set-Secret -Name 'GitHubPS.AccessToken.ExpirationDate' -Secret $accessTokenExpirationDate.toString() -Vault $vault.Name
Set-Secret -Name 'GitHubPS.RefreshToken' -Secret $refreshToken -Vault $vault.Name
Set-Secret -Name 'GitHubPS.RefreshToken.ExpirationDate' -Secret $refreshTokenExpirationDate.toString() -Vault $vault.Name
Set-Secret -Name 'GitHubPS.Scope' -Secret $tokenScope -Vault $vault.Name
Set-Secret -Name 'GitHubPS.AuthMode' -Secret $script:AuthMode -Vault $vault.Name
}

Set-Secret -Name 'GitHubPS.AuthMode' -Secret $script:AuthMode -Vault $vault.Name

$user = Get-GitHubUser
Write-Host '' -ForegroundColor Green -NoNewline
Write-Host "Logged in as $($user.name) (@$($user.login))!"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function Invoke-GitHubDeviceCodeLogin {
function Invoke-GitHubDeviceFlowLogin {
<#
.SYNOPSIS
Starts the GitHub Device Flow login process.
Expand All @@ -7,7 +7,7 @@
Starts the GitHub Device Flow login process. This will prompt the user to visit a URL and enter a code.
.EXAMPLE
Invoke-GitHubDeviceCodeLogin
Invoke-GitHubDeviceFlowLogin
This will start the GitHub Device Flow login process.
The user gets prompted to visit a URL and enter a code.
Expand All @@ -32,31 +32,36 @@
# For more information on scopes visit:
# https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps
[Parameter()]
[string] $Scope
[string] $Scope,

# Refresh the access token.
[Parameter()]
[switch] $Refresh
)

$script:AuthMode = $Mode

$script:ClientID = switch ($Mode) {
'OAuthApp' { $script:GitHubOAuthAppClientID }
'GitHubApp' { $script:GitHubAppClientID }
}
$script:ClientID = Get-GitHubDeviceFlowClientID -Mode $Mode

do {
$deviceCodeResponse = Request-GitHubDeviceCode -ClientID $ClientID -Scope $Scope
if ($Refresh) {
$tokenResponse = Wait-GitHubToken -ClientID $script:ClientID
} else {
$deviceCodeResponse = Request-GitHubDeviceCode -ClientID $ClientID -Scope $Scope

$deviceCode = $deviceCodeResponse.device_code
$interval = $deviceCodeResponse.interval
$userCode = $deviceCodeResponse.user_code
$verificationUri = $deviceCodeResponse.verification_uri
$deviceCode = $deviceCodeResponse.device_code
$interval = $deviceCodeResponse.interval
$userCode = $deviceCodeResponse.user_code
$verificationUri = $deviceCodeResponse.verification_uri

Write-Host '! ' -ForegroundColor DarkYellow -NoNewline
Write-Host "We added the code to your clipboard: [$userCode]"
$userCode | Set-Clipboard
Read-Host 'Press Enter to open github.com in your browser...'
Start-Process $verificationUri
Write-Host '! ' -ForegroundColor DarkYellow -NoNewline
Write-Host "We added the code to your clipboard: [$userCode]"
$userCode | Set-Clipboard
Read-Host 'Press Enter to open github.com in your browser...'
Start-Process $verificationUri

$tokenResponse = Wait-GitHubToken -DeviceCode $deviceCode -ClientID $ClientID -Interval $interval
$tokenResponse = Wait-GitHubToken -DeviceCode $deviceCode -ClientID $ClientID -Interval $interval
}
} while ($tokenResponse.error)
$tokenResponse
}
10 changes: 5 additions & 5 deletions src/GitHub/public/DeviceFlow/Request-GitHubToken.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
https://docs.github.com/en/apps/creating-github-apps/writing-code-for-a-github-app/building-a-cli-with-a-github-app
#>
[OutputType([PSCustomObject])]
[CmdletBinding(DefaultParameterSetName = 'DeviceCode')]
[CmdletBinding(DefaultParameterSetName = 'DeviceFlow')]
param(
# The Client ID of the GitHub App.
[Parameter(Mandatory)]
[string] $ClientID,

# The `device_code` used to request the access token.
# The 'device_code' used to request the access token.
[Parameter(
Mandatory,
ParameterSetName = 'DeviceCode'
ParameterSetName = 'DeviceFlow'
)]
[string] $DeviceCode,

Expand All @@ -39,8 +39,8 @@
)

$body = @{
'client_id' = $ClientID
'grant_type' = 'urn:ietf:params:oauth:grant-type:device_code'
'client_id' = $ClientID
'grant_type' = 'urn:ietf:params:oauth:grant-type:device_code'
}

if ($PSBoundParameters.ContainsKey('RefreshToken')) {
Expand Down
33 changes: 25 additions & 8 deletions src/GitHub/public/DeviceFlow/Wait-GitHubToken.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,38 @@ function Wait-GitHubToken {
[OutputType([PSCustomObject])]
[CmdletBinding()]
param(
# The `device_code` used to request the token.
[Parameter(Mandatory)]
# The 'device_code' used to request the token.
[Parameter(
Mandatory,
ParameterSetName = 'DeviceFlow'
)]
[string] $DeviceCode,

# Refresh the access token.
[Parameter(
Mandatory,
ParameterSetName = 'Refresh'
)]
[switch] $Refresh,

# The Client ID of the GitHub App.
[Parameter()]
[string] $ClientID,

# The interval to wait between polling for the token.
[Parameter()]
[Parameter(
ParameterSetName = 'DeviceFlow'
)]
[int] $Interval = 5

)

do {
$response = Request-GitHubToken -DeviceCode $DeviceCode -ClientID $ClientID
if ($Refresh) {
$response = Request-GitHubToken -Refresh -ClientID $ClientID -RefreshToken $script:RefreshToken
} else {
$response = Request-GitHubToken -DeviceCode $DeviceCode -ClientID $ClientID
}
if ($response.error) {
switch ($response.error) {
'authorization_pending' {
Expand All @@ -52,22 +69,22 @@ function Wait-GitHubToken {
continue
}
'expired_token' {
# The `device_code` expired, and the process needs to restart.
# The 'device_code' expired, and the process needs to restart.
Write-Error $response.error_description
exit 1
}
'unsupported_grant_type' {
# The `grant_type` is not supported.
# The 'grant_type' is not supported.
Write-Error $response.error_description
exit 1
}
'incorrect_client_credentials' {
# The `client_id` is not valid.
# The 'client_id' is not valid.
Write-Error $response.error_description
exit 1
}
'incorrect_device_code' {
# The `device_code` is not valid.
# The 'device_code' is not valid.
Write-Error $response.error_description
exit 2
}
Expand Down
14 changes: 14 additions & 0 deletions src/GitHub/public/loader.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,17 @@ if ($secrets.name -contains 'GitHubPS.Version') {
if ($secrets.name -contains 'GitHubPS.ContentType') {
$script:ContentType = Get-Secret -Name 'GitHubPS.ContentType' -AsPlainText
}

if ($secrets.name -contains 'GitHubPS.AuthMode') {
$script:AuthMode = Get-Secret -Name 'GitHubPS.AuthMode' -AsPlainText
}

if (($secrets.name -contains 'GitHubPS.AccessToken.ExpirationDate') -and $secrets.name -contains 'GitHubPS.RefreshToken') {
$script:RefreshToken = Get-Secret -Name 'GitHubPS.RefreshToken' -AsPlainText
[DateTime]$accessTokenExirationDate = Get-Secret -Name 'GitHubPS.AccessToken.ExpirationDate' -AsPlainText -ErrorAction SilentlyContinue
$accessTokenValid = $accessTokenExirationDate -gt (Get-Date)
if (-not $accessTokenValid) {
Write-Warning "Your access token has expired. Refreshing it..."
Connect-GitHubAccount -Refresh
}
}

0 comments on commit 6fd7e21

Please sign in to comment.