Alright. I’ve come up with a solution. It wasn’t quite as straight forward as I first thought but it works.
I have 2 apps.
New-PSUApp -Name "a" -FilePath "dashboards\a\a.ps1" -BaseUrl "/app" -AutoDeploy
New-PSUApp -Name "App2" -FilePath "dashboards\App2\App2.ps1" -BaseUrl "/app2" -Authenticated -AutoDeploy
/app is used for the login. The idea with this is that the user enters their email address. For my test, I’m just setting a URL into the clipboard but this would be the URL you would include with the email.
We generate a passcode and include it in the query string for the URL. We set that passcode into the server cache with a 5 minute expiration. We redirect back to this dashboard and construct a JavaScript command that calls the login API with the user name and passcode.
New-UDApp -Content {
if ($Query["passcode"]) {
New-UDDynamic -Content {
$JavaScript = "fetch('http://localhost:5000/api/v1/signin', {
method: 'POST',
body: JSON.stringify({
username: '$($Query['email'])',
password: '$($Query['passcode'])'
}),
credentials: 'include',
headers: {
'Content-type': 'application/json; charset=UTF-8'
}
})
.then((response) => response.json()).
then(() => {
window.location.href = 'http://localhost:5000/app2'
});"
Invoke-UDJavaScript -JavaScript $JavaScript
}
}
else {
New-UDForm -Content {
New-UDTextbox -Placeholder "Email" -Id 'email' -Type email
} -OnSubmit {
$Password = (New-Guid).ToString()
# Send Email Here with a link like: http://localhost:5000/app?email=email&passcode=$Password
# For Testing
Set-UDClipboard -Data "http://localhost:5000/app/Home?email=$($EventData.email)&passcode=$Password" -ToastOnSuccess
# Set cache with email + passcode. User has 5 minutes to click link in email before it expires
Set-PSUCache -Key $EventData.email -Value $Password -AbsoluteExpirationFromNow ([TimeSpan]::FromMinutes(5))
New-UDAlert -Text "Please check your email!"
} -SubmitText "Send Login Email"
}
}
After submitting the form, the user will see this.
A URL is generated and set into the clipboard.
http://localhost:5000/app/Home?email=adam@ironmansoftware.com&passcode=618cbbb2-a9c0-4be3-9cf1-6b4c7fa69beb
Visiting this URL will run the same app again but extract the email and pass code from the query string. It will then invoke the JS from the user’s browser and redirect them to the authenticated app2.
App2 just consists of a display of the username and roles.
New-UDApp -Title 'PowerShell Universal' -Content {
New-UDTypography $User
$Roles | ForEach-Object {
New-UDChip -Label $_
}
}
The secret sauce actually consists of implementing a form login that can check the server cache for email + passcode pairs. If they are valid, then we can authenticate the user and assign a role.
param(
[PSCredential]$Credential
)
# Check the cache to see if this email + passcode combination is valid
$Passcode = Get-PSUCache -Key $Credential.UserName
if ($Passcode -eq $Credential.GetNetworkCredential().Password) {
New-PSUAuthenticationResult -Claims {
New-PSUAuthorizationClaim -Type ([System.Security.Claims.ClaimTypes]::Role) -Value 'Administrator'
} -UserName $Credential.UserName -Success
}
# Do standard form login here
New-PSUAuthenticationResult -ErrorMessage 'Bad username or password'