Created
September 29, 2023 00:41
-
-
Save mahnunchik/596637aaa81d078ef76e2d9e828d0a3c to your computer and use it in GitHub Desktop.
WebAuthn Electron
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> | |
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://webauthn.io/; script-src 'self' 'unsafe-inline' https://unpkg.com/; style-src 'self' 'unsafe-inline'"> | |
<title>Hello World!</title> | |
<script src="https://unpkg.com/@simplewebauthn/browser"></script> | |
</head> | |
<body> | |
<h1>Hello World!</h1> | |
<div> | |
We are using Node.js <span id="node-version"></span>, | |
Chromium <span id="chrome-version"></span>, | |
and Electron <span id="electron-version"></span>. | |
</div> | |
<div> | |
<p>browserSupportsWebAuthn: <span id="browserSupportsWebAuthn"></span><p> | |
<p>browserSupportsWebAuthnAutofill: <span id="browserSupportsWebAuthnAutofill"></span><p> | |
</div> | |
<div class="col-sm-12 mb-3"> | |
<input | |
type="text" | |
id="username" | |
placeholder="example_username" | |
x-model="username" | |
autocomplete="username webauthn" | |
/> | |
</div> | |
<button | |
id="register-button" | |
onclick="startRegistration()" | |
> | |
Register | |
</button> | |
<button | |
id="register-button" | |
onclick="startAuthentication()" | |
> | |
Authenticate | |
</button> | |
<script type="module" src="./renderer.js"></script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { app, protocol, net, BrowserWindow } = require('electron') | |
const path = require('path') | |
const { pathToFileURL } = require('url'); | |
function createWindow () { | |
const mainWindow = new BrowserWindow({ | |
width: 800, | |
height: 600, | |
}) | |
mainWindow.loadURL('https://webauthn.io/') | |
mainWindow.webContents.openDevTools() | |
} | |
app.whenReady().then(() => { | |
protocol.handle('https', (req) => { | |
const { host, pathname } = new URL(req.url); | |
if (host === 'webauthn.io' && (pathname === '/' || pathname === '/renderer.js' )) { | |
const url = new URL('.' + (pathname === '/' ? '/index.html' : pathname), pathToFileURL(__filename)); | |
return net.fetch(url); | |
} | |
return net.fetch(req, { bypassCustomProtocolHandlers: true }); | |
}); | |
createWindow() | |
app.on('activate', function () { | |
if (BrowserWindow.getAllWindows().length === 0) createWindow() | |
}) | |
}) | |
app.on('window-all-closed', function () { | |
if (process.platform !== 'darwin') app.quit() | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "lumpy-dime-set-9mmzx", | |
"productName": "lumpy-dime-set-9mmzx", | |
"description": "My Electron application description", | |
"keywords": [], | |
"main": "./main.js", | |
"version": "1.0.0", | |
"author": "evlasenko", | |
"scripts": { | |
"start": "electron ." | |
}, | |
"dependencies": {}, | |
"devDependencies": { | |
"electron": "26.2.2" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The preload script runs before. It has access to web APIs | |
* as well as Electron's renderer process modules and some | |
* polyfilled Node.js functions. | |
* | |
* https://www.electronjs.org/docs/latest/tutorial/sandbox | |
*/ | |
window.addEventListener('DOMContentLoaded', () => { | |
const replaceText = (selector, text) => { | |
const element = document.getElementById(selector) | |
if (element) element.innerText = text | |
} | |
for (const type of ['chrome', 'node', 'electron']) { | |
replaceText(`${type}-version`, process.versions[type]) | |
} | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
document.getElementById('browserSupportsWebAuthn').innerHTML = SimpleWebAuthnBrowser.browserSupportsWebAuthn(); | |
document.getElementById('browserSupportsWebAuthnAutofill').innerHTML = await SimpleWebAuthnBrowser.browserSupportsWebAuthnAutofill(); | |
window.startRegistration = async function startRegistration() { | |
const username = document.getElementById('username').value; | |
if (!username) { | |
console.error('Please enter a username to register'); | |
return; | |
} | |
const apiRegOptsResp = await fetch('https://webauthn.io/registration/options', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({ | |
username, | |
// e.g. 'preferred' | |
user_verification: 'preferred', | |
// e.g. 'direct' | |
attestation: 'none', | |
// e.g. 'platform' | |
attachment: 'all', | |
// e.g. ['es256', 'rs256'] | |
//algorithms, | |
// e.g. 'preferred' | |
discoverable_credential: 'preferred', | |
}), | |
}); | |
const registrationOptionsJSON = await apiRegOptsResp.json(); | |
console.log('REGISTRATION OPTIONS'); | |
console.log(JSON.stringify(registrationOptionsJSON, null, 2)); | |
// Start WebAuthn registration | |
const regResp = await SimpleWebAuthnBrowser.startRegistration(registrationOptionsJSON); | |
console.log('REGISTRATION RESPONSE'); | |
console.log(JSON.stringify(regResp, null, 2)); | |
// Submit response | |
const apiRegVerResp = await fetch('https://webauthn.io/registration/verification', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({ | |
username, | |
response: regResp, | |
}), | |
}); | |
const verificationJSON = await apiRegVerResp.json() | |
// Display outcome | |
if (verificationJSON.verified === true) { | |
console.log('Success! Now try to authenticate...'); | |
} else { | |
console.error(`Registration failed: ${verificationJSON.error}`); | |
} | |
} | |
window.startAuthentication = async function startAuthentication(startConditionalUI = false) { | |
const username = document.getElementById('username').value; | |
if (!username) { | |
console.error('Please enter a username to register'); | |
return; | |
} | |
// Submit options | |
const apiAuthOptsResp = await fetch('https://webauthn.io/authentication/options', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({ | |
username, | |
user_verification: 'preferred', | |
}), | |
}); | |
const authenticationOptionsJSON = await apiAuthOptsResp.json(); | |
console.log('AUTHENTICATION OPTIONS'); | |
console.log(JSON.stringify(authenticationOptionsJSON, null, 2)); | |
if (authenticationOptionsJSON.error) { | |
console.error(authenticationOptionsJSON.error); | |
return; | |
} | |
// Start WebAuthn authentication | |
const authResp = await SimpleWebAuthnBrowser.startAuthentication(authenticationOptionsJSON, startConditionalUI); | |
console.log('AUTHENTICATION RESPONSE'); | |
console.log(JSON.stringify(authResp, null, 2)); | |
// Submit response | |
const apiAuthVerResp = await fetch('https://webauthn.io/authentication/verification', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({ | |
username, | |
response: authResp, | |
}), | |
}); | |
const verificationJSON = await apiAuthVerResp.json() | |
if (verificationJSON.verified === true) { | |
console.log('Authentication Success!'); | |
} else { | |
console.error(`Authentication failed: ${verificationJSON.error}`); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* styles.css */ | |
/* Add styles here to customize the appearance of your app */ |
@mahnunchik I was thinking of testing this out with Ferdium, do you know where to add your workaround in that case?
I get this error
FIDO: fido_discovery_factory.cc:70 Cannot use Bluetooth because the responsible app for the process does not have Bluetooth metadata in its Info.plist. Launch from Finder to fix.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@juanluisbaptiste please use simple layout from electron quick start https://github.com/electron/electron-quick-start