Skip to content
Open
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
43 changes: 43 additions & 0 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ jobs:

runs-on: windows-latest

permissions:
id-token: write # for Azure OIDC login used by code signing
contents: read

strategy:
matrix:
include:
Expand All @@ -34,6 +38,45 @@ jobs:
- name: Publish
run: dotnet publish ${{ env.ProjectName }} --no-build --runtime ${{ matrix.targetPlatform }} --configuration Release --no-self-contained -p:PublishSingleFile=true

# Signing is required for the uiAccess privilege
- name: Azure login
uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

- name: Install AzureSignTool
run: dotnet tool install --global AzureSignTool

- name: Sign
env:
KEY_VAULT_URL: ${{ vars.KEY_VAULT_URL }}
KEY_VAULT_CERT: ${{ vars.KEY_VAULT_CERT }}
run: |
$exe = Get-ChildItem "${{ env.ProjectName }}/bin/Release/net8.0-windows/${{ matrix.targetPlatform }}/publish/*.exe"
AzureSignTool sign -kvu $env:KEY_VAULT_URL -kvc $env:KEY_VAULT_CERT -kvm -tr http://timestamp.acs.microsoft.com -td sha256 -fd sha256 $exe.FullName

- name: Build installer
run: |
choco install innosetup --no-progress -y
curl.exe -fsSL https://raw.githubusercontent.com/DomGries/InnoDependencyInstaller/master/CodeDependencies.iss -o ${{ env.ProjectName }}/CodeDependencies.iss
$exe = (Get-Item "${{ env.ProjectName }}/bin/Release/net8.0-windows/${{ matrix.targetPlatform }}/publish/${{ env.ProjectName }}.exe").FullName
$version = (Get-Item $exe).VersionInfo.FileVersion
& "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe" `
/DArch=${{ matrix.targetPlatform }} `
/DSourceExe="$exe" `
/DAppVersion="$version" `
${{ env.ProjectName }}/Setup.iss

- name: Sign installer
env:
KEY_VAULT_URL: ${{ vars.KEY_VAULT_URL }}
KEY_VAULT_CERT: ${{ vars.KEY_VAULT_CERT }}
run: |
$installer = Get-ChildItem "${{ env.ProjectName }}/bin/Release/net8.0-windows/${{ matrix.targetPlatform }}/publish/*-Setup.exe"
AzureSignTool sign -kvu $env:KEY_VAULT_URL -kvc $env:KEY_VAULT_CERT -kvm -tr http://timestamp.acs.microsoft.com -td sha256 -fd sha256 $installer.FullName

- name: Upload build artifacts
uses: actions/upload-artifact@v7
with:
Expand Down
51 changes: 51 additions & 0 deletions AuthenticatorChooser/Setup.iss
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
; Inno Setup script for AuthenticatorChooser, compiled in CI.
; ISCC is invoked with /DArch=win-x64|win-arm64, /DSourceExe=<absolute path to signed exe> and /DAppVersion=<version>.

#define AppName "AuthenticatorChooser"
#define AppExeName "AuthenticatorChooser.exe"
#define AppPublisher "Ben Hutchison"

#if Arch == "win-arm64"
#define ArchId "arm64"
#else
#define ArchId "x64compatible"
#endif

[Setup]
AppId={{ce8383a4-bdac-4d97-b0a6-8fc582b4c102}
AppName={#AppName}
AppVersion={#AppVersion}
AppPublisher={#AppPublisher}
DefaultDirName={autopf}\{#AppName}
DisableProgramGroupPage=yes
PrivilegesRequired=admin
ArchitecturesAllowed={#ArchId}
ArchitecturesInstallIn64BitMode={#ArchId}
UninstallDisplayIcon={app}\{#AppExeName}
; Emit the installer into the publish folder so it's uploaded alongside the main binary.
OutputDir=bin\Release\net8.0-windows\{#Arch}\publish
OutputBaseFilename={#AppName}-{#AppVersion}-{#Arch}-Setup
Compression=lzma2
SolidCompression=yes

[Files]
Source: "{#SourceExe}"; DestDir: "{app}"; Flags: ignoreversion

[Icons]
Name: "{userstartup}\{#AppName}"; Filename: "{app}\{#AppExeName}"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires installation as the user, so it doesn't work on

  • devices with multiple users
  • installation with EPM elevation
  • installation as SYSTEM without a helper like PSADT

I could use {commonstartup}, but then users can't modify the args without admin privs


[Run]
Filename: "{app}\{#AppExeName}"; Description: "Start {#AppName} now"; Flags: nowait runascurrentuser

[UninstallRun]
Filename: "{sys}\taskkill.exe"; Parameters: "/im {#AppExeName} /f"; Flags: runhidden; RunOnceId: "StopApp"

; https://github.com/DomGries/InnoDependencyInstaller - downloads and installs the .NET Desktop Runtime 8 if it's missing
#include "CodeDependencies.iss"

[Code]
function InitializeSetup: Boolean;
begin
Dependency_AddDotNet80Desktop;
Result := True;
end;
4 changes: 2 additions & 2 deletions AuthenticatorChooser/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ private bool registerAsStartupProgram() {
scheduledTask.RegistrationInfo.Author = "Ben Hutchison";
scheduledTask.RegistrationInfo.Date = DateTime.Now;
scheduledTask.RegistrationInfo.Description =
$"{PROGRAM_NAME} is a background program that skips the phone pairing option and chooses the USB security key in Windows FIDO/WebAuthn prompts. \n\nThis scheduled task is necessary to start {PROGRAM_NAME} for you on login with elevated permissions, which are required to interact with the Windows 11 FIDO prompts beginning in January 2026. \n\nhttps://github.com/Aldaviva/{PROGRAM_NAME}";
scheduledTask.Principal.RunLevel = TaskRunLevel.Highest; // #44: CredentialUIBroker runs with UIAccess integrity level, which is higher than the default Medium level
$"{PROGRAM_NAME} is a background program that skips the phone pairing option and chooses the USB security key in Windows FIDO/WebAuthn prompts. \n\nThis scheduled task starts {PROGRAM_NAME} for you on login. {PROGRAM_NAME} uses UIAccess (declared in its application manifest) to interact with the Windows 11 FIDO prompts beginning in January 2026, so it no longer needs to run elevated. \n\nhttps://github.com/Aldaviva/{PROGRAM_NAME}";
scheduledTask.Principal.RunLevel = TaskRunLevel.LUA; // #44: CredentialUIBroker runs at the UIAccess integrity level; the app's uiAccess="true" manifest lets it interact without elevation, so run as a standard user (LUA) instead of Highest
scheduledTask.Settings.Enabled = true;
scheduledTask.Settings.ExecutionTimeLimit = TimeSpan.Zero;
scheduledTask.Settings.DisallowStartIfOnBatteries = false;
Expand Down
3 changes: 2 additions & 1 deletion AuthenticatorChooser/app.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<!-- The CredentialUIBroker FIDO prompt runs with UIAccess since Jan 2026 https://github.com/Aldaviva/AuthenticatorChooser/issues/44 -->
<requestedExecutionLevel level="asInvoker" uiAccess="true" />
</requestedPrivileges>
</security>
</trustInfo>
Expand Down
14 changes: 12 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,24 @@ Even if this program doesn't click the Next button (because an extra choice was

## Installation

### Installer

1. [Download the latest `Setup.exe` installer for your CPU architecture.](https://github.com/Aldaviva/AuthenticatorChooser/releases/latest)
1. Run it. It installs the [.NET Desktop Runtime 8](https://dotnet.microsoft.com/en-us/download/dotnet/8.0/runtime) if it's missing, installs to `C:\Program Files\AuthenticatorChooser\`, starts the program, and adds a Startup shortcut so it launches automatically each time you log in.
1. If you'd like to specify additional [command-line arguments](https://github.com/Aldaviva/AuthenticatorChooser/wiki/Command%E2%80%90line-arguments) like `--skip-all-non-security-key-options`, open your Startup folder (press <kbd>⊞ Win</kbd>+<kbd>R</kbd> and enter `shell:startup`), then edit the `AuthenticatorChooser` shortcut and append the arguments to its `Target`.

### Manual (ZIP)

1. [Download the latest release ZIP archive for your CPU architecture.](https://github.com/Aldaviva/AuthenticatorChooser/releases/latest)
1. Extract the `AuthenticatorChooser.exe` file from the ZIP archive to a directory of your choice, like `C:\Program Files\AuthenticatorChooser\`.
1. Extract the `AuthenticatorChooser.exe` file from the ZIP archive to a directory in `C:\Program Files\`, like `C:\Program Files\AuthenticatorChooser\`.
1. Run the program by double-clicking `AuthenticatorChooser.exe`.
- Nothing will appear because it's a background program with no UI, but you can tell it's running by searching for `AuthenticatorChooser` in Task Manager.
1. Register the program to run automatically on user logon with **any one** of the following techniques. If you'd like to specify additional [command-line arguments](https://github.com/Aldaviva/AuthenticatorChooser/wiki/Command%E2%80%90line-arguments) like `--skip-all-non-security-key-options`, you can do that here too.
- Run this program once with the `--autostart-on-logon` argument
```ps1
.\AuthenticatorChooser --autostart-on-logon
```
- Manually add a new task to Task Scheduler that starts `AuthenticatorChooser.exe` as your user with highest privileges when you log in to Windows
- Manually add a new task to Task Scheduler that starts `AuthenticatorChooser.exe` as your user when you log in to Windows

## Demo

Expand Down Expand Up @@ -99,6 +107,8 @@ The program will be compiled to the following path, assuming your CPU architectu
.\bin\Release\net8.0-windows\win-x64\publish\AuthenticatorChooser.exe
```

To test, sign the exe with a certificate trusted by your device (it can be self-signed). Then copy the exe to `C:\Program Files\AuthenticatorChooser\`.

You can also use an IDE like [Visual Studio](https://visualstudio.microsoft.com/vs/) Community 2022 or 2026 instead of the command line if you prefer.

- Visual Studio Publishing Profiles have been [broken for years](https://developercommunity.visualstudio.com/t/Trying-to-publish-to-a-folder-only-build/10905900) unless certain other workloads (like ASP.NET Web Development) are installed, so if you can't publish from VS you'll have to use the `dotnet publish` command above.
Expand Down