Skip to content
This repository has been archived by the owner on Jun 13, 2022. It is now read-only.

Commit

Permalink
Merge 3940d6a into 54fc3fa
Browse files Browse the repository at this point in the history
  • Loading branch information
DarkGhostHunter committed Jul 4, 2020
2 parents 54fc3fa + 3940d6a commit 5e9257e
Show file tree
Hide file tree
Showing 3 changed files with 365 additions and 40 deletions.
113 changes: 73 additions & 40 deletions README.md
Expand Up @@ -35,6 +35,7 @@ If you have any doubts about WebAuthn, [check this small FAQ](#faq).
2. Migrate the `webauthn_credentials` table.
3. Implement the `WebAuthnAuthenticatable` contract and `WebAuthnAuthentication` trait to your User(s) classes.
4. Register WebAuthn routes.
4. Add the Javascript helper.

### 1. Add the `eloquent-webauthn` driver.

Expand Down Expand Up @@ -113,29 +114,80 @@ In your frontend scripts, point the requests to these routes.

> If you want full control, you can opt-out of these helper controllers and use your own logic. Use the [`AttestWebAuthn`](src/Http/AttestsWebAuthn.php) and [`AssertsWebAuthn`](src/Http/AssertsWebAuthn.php) traits if you need to start with something.
## Frontend integration
### 5. Frontend integration

You're in charge of registering and authenticating users as you want using your own scripts in your frontend. **Larapass doesn't include scripts** because there is no best all-around script that cover all use cases (Vue.js, React.js, vanilla Javascript, etc).
This package includes a convenient script to handle registration and login via WebAuthn. To use it, just publish the `larapass.js` asset into your application public resources.

The important bit is to point the _attest_ (registration) and _assert_ (login) to the routes used for each of them.
php artisan vendor:publish --provider="DarkGhostHunter\Larapass\LarapassServiceProvider" --tag="public"

If you want to start with something, I recommend these [WebAuthn Javascript Helpers](https://github.com/web-auth/webauthn-helper) which are simple and straightforward.
You will receive the `vendor/larapass/js/larapass.js` file which you can include into your authentication views and use it programmatically, anyway you want.

```html
<script src="{{ asset('vendor/larapass/js/larapass.js') }}"></script>

<!-- Registering users -->
<script>
const register = () => {
new Larapass({
register: 'webauthn/register',
registerOptions: 'webauthn/register/options'
}).register()
.then(response => window.location.href = 'https://myapp.com/devices')
.catch(response => alert('Something went wrong, try again!'))
}
document.getElementById('register-form').addEventListener('submit', register)
</script>

<!-- Login users -->
<script>
const login = () => {
new Larapass({
login: 'webauthn/register',
loginOptions: 'webauthn/register/options'
}).login({
email: document.getElementById('email').value,
}).then(response => window.location.href = 'https://myapp.com/account')
.catch(error => alert('Something went wrong, try again!'))
}
document.getElementById('login-form').addEventListener('submit', login)
</script>
```

You can bypass the route list declaration if you're using the defaults. The example above includes them just for show.

Also, the helper allows headers on the action request, on both registration and login.

```javascript
import {useLogin} from 'webauthn-helper';
new Larapass({
login: 'webauthn/register',
loginOptions: 'webauthn/register/options'
}).login({
email: document.getElementById('email').value,
}, {
myHeader: 'This is sent with the signed challenge',
})
```

const login = useLogin({
loginOptions: '/webauthn/login/options',
loginUrl: '/webauthn/login',
});
> If the script doesn't suit your needs, you're free to create your own script to handle WebAuthn, or just copy-paste it and import into a transpiler like [Laravel Mix](https://laravel.com/docs/mix#running-mix), [Babel](https://babeljs.io/) or [Webpack](https://webpack.js.org/).
login({
username: 'John Doe'
### Remembering Users

You can enable it by just issuing the `WebAuthn-Remember` header value to `true` when pushing the signed login challenge from your frontend. We can do this easily with the [included Javascript helper](#5-frontend-integration).

```javascript
new Larapass.login({
email: document.getElementById('email').value
}, {
'WebAuthn-Remember': true
})
.then(response => window.location.replace = 'https://myapp.com/welcome')
.catch(error => console.log(error));
```

Alternatively, you can add the `remember` key to the outgoing JSON Payload if you're using your own scripts. Both ways are accepted.

> You can override this behaviour in the [`AssertsWebAuthn`](src/Http/AssertsWebAuthn.php) trait.
## Events

Since all authentication is handled by Laravel itself, the only [event](https://laravel.com/docs/events) included is [`AttestationSuccessful`](src/Events/AttestationSuccessful.php), which fires when the registration is successful. It includes the user and the credentials persisted.
Expand Down Expand Up @@ -395,25 +447,6 @@ By default, this package allows to re-use the same `eloquent-webauthn` driver to

Disabling the fallback will only check for WebAuthn credentials. To handle classic user/password scenarios, you should create a separate guard.

## Remembering Users

You can enable it by just issuing the `WebAuthn-Remember` header value to `true` when pushing the signed login challenge from your frontend, or adding the `remember` key to the JSON Payload if you're able to.

```javascript
fetch('/webauthn/login', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'WebAuthn-Remember': true,
},
body: JSON.stringify(publicKeyCredentialsSource),
})
```

> You can override this in the [`AssertsWebAuthn`](src/Http/AssertsWebAuthn.php) trait.
## Attestation and Metadata statements support

If you need very-high-level of security, you should use attestation and metadata statements. You will basically ask the authenticator for its authenticity and check it in a lot of ways.
Expand Down Expand Up @@ -451,10 +484,10 @@ If you discover any security related issues, please email darkghosthunter@gmail.

* **Does this work with any browser?**

[Yes](https://caniuse.com/#feat=webauthn). In the case of old browsers, you should have a fallback detection script:
[Yes](https://caniuse.com/#feat=webauthn). In the case of old browsers, you should have a fallback detection script. This can be asked with [the included Javascript helper](#5-frontend-integration) in a breeze:

```javascript
if (typeof(PublicKeyCredential) == "undefined") {
if (! Larapass.supportsWebAuthn()) {
alert('Your device is not secure enough to use this site!');
}
```
Expand Down Expand Up @@ -489,7 +522,7 @@ $this->app->bind(CounterChecker::class, function () {
});
```

Then, you can add your logic to .
Inside your counter checker, you may want to throw an exception if the counter is below what is reported.

```php
<?php
Expand All @@ -515,23 +548,23 @@ class MyCountChecker implements CounterChecker

Yes, just send him a signed email to register a new device with secure attestation and assertion routes. That's up to you.

> To blacklist a device, use `disableDevice()` in the user instance.
> To blacklist a device, use `disableDevice()` in the user instance. That allows the user to re-enable it when he recovers the device.
* **How secure is this against passwords or 2FA?**

Extremely secure since it works only on HTTPS, and no password or codes are exchanged after registration.

* **Can I deactivate the password fallback? Can I enforce only WebAuthn authentication?**

Yes. Just be sure to disable the password column in the users table, the Password Broker, and have some logic to register new devices and invalidate old ones. The [`WebAuthnAuthentication`](src/WebAuthnAuthentication.php) trait helps with this.
Yes. Just be sure to disable the password column in the users table, the Password Broker, and have some logic to recover the account with new devices and invalidate old ones. The [`WebAuthnAuthentication`](src/WebAuthnAuthentication.php) trait helps with this.

* **Does this includes Javascript?**
* **Does this includes a frontend Javascript?**

No, mainly because each application frontend is different. A given script may not work for you.
[Yes.](#5-frontend-integration)

* **Does this encodes/decode the strings automatically in the frontend?**

No, you must ensure to encode/decode to binary forms some strings in your frontend because the nature of WebAuthn. This [WebAuthn Javascript Helpers](https://github.com/web-auth/webauthn-helper) package does it automatically for you.
No, you must ensure to encode/decode to binary forms some strings in your frontend because the nature of WebAuthn. The included [WebAuthn Helper](#5-frontend-integration) does it automatically for you.

## License

Expand Down

0 comments on commit 5e9257e

Please sign in to comment.