Skip to content

Commit

Permalink
Merge branch 'main' into android
Browse files Browse the repository at this point in the history
  • Loading branch information
jonashendrickx authored Jan 7, 2024
2 parents c4ad0ed + 6647a2a commit 4aadb8b
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 49 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Install NodeJS
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version: 18

Expand Down
40 changes: 40 additions & 0 deletions renovate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base",
":combinePatchMinorReleases",
":dependencyDashboard",
":maintainLockFilesWeekly",
":pinAllExceptPeerDependencies",
":prConcurrentLimit10",
":rebaseStalePrs",
":separateMajorReleases",
"group:monorepos",
"schedule:weekends"
],
"enabledManagers": ["cargo", "github-actions", "npm", "nuget"],
"commitMessagePrefix": "[deps]:",
"commitMessageTopic": "{{depName}}",
"packageRules": [
{
"groupName": "cargo minor",
"matchManagers": ["cargo"],
"matchUpdateTypes": ["minor", "patch"]
},
{
"groupName": "gh minor",
"matchManagers": ["github-actions"],
"matchUpdateTypes": ["minor", "patch"]
},
{
"groupName": "npm minor",
"matchManagers": ["npm"],
"matchUpdateTypes": ["minor", "patch"]
},
{
"groupName": "nuget minor",
"matchManagers": ["nuget"],
"matchUpdateTypes": ["minor", "patch"]
}
]
}
114 changes: 87 additions & 27 deletions src/guide/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ The request body may include additional parameters besides those required, all o
| `discoverable` | If `true`, creates a client-side Discoverable Credential that allows sign in without needing a username. | `true` (default) |
| `userVerification` | Allows choosing preference for requiring User Verification (biometrics, pin code etc) when authenticating Can be `"preferred"` (default), `"required"` or `"discouraged"`. | `"preferred"` |
| `expiresAt` | Timestamp (UTC) when the registration token should expire. By default, current time + 120 seconds. | `"3023-08-01T14:43:03Z"` |
| `aliases` | A array of aliases for the userId, such as an email or username. Used to initiate a signin on the client side with the `signinWithAlias()` method. An alias must be unique to the userId. Defaults to an empty array `[]`. | `["[email protected]"]` |
| `aliases` | A array of aliases for the userId, such as an email or username. Used to initiate a sign-in on the client side with the `signinWithAlias()` method. An alias must be unique to the userId. Defaults to an empty array `[]`. | `["[email protected]"]` |
| `aliasHashing` | Whether aliases should be hashed before being stored. Defaults to `true`. | `true` |

### Response
Expand All @@ -86,7 +86,7 @@ This registration token will will be used by your frontend to negotiate creation

### Request

`POST` requests made to the `/signin` endpoint unpack a [verification token](concepts.md#tokens), which must be generated by calling a `.signinWith*()` method on your frontend ([learn more](frontend/javascript.md#signinwith)) and included here in the request body, for example:
`POST` requests made to the `/signin/verify` endpoint unpack an [authentication token](concepts.md#tokens), which must be generated by calling a `.signinWith*()` method on your frontend ([learn more](frontend/javascript.md#signinwith)) and included here in the request body, for example:

<CodeSwitcher :languages="{http:'HTTP',js:'JavaScript'}">
<template v-slot:http>
Expand All @@ -107,13 +107,13 @@ Content-Type: application/json
```js
const apiUrl = 'https://v4.passwordless.dev';

// Fetch the verification token from your frontend.
const token = { token: req.query.token };
// Fetch the authentication token from your frontend.
const payload = { token: req.query.token };

// POST the verification token to the Passwordless.dev API using your API private secret.
// POST the authentication token to the Passwordless.dev API using your API private secret.
const response = await fetch(apiUrl + '/signin/verify', {
method: 'POST',
body: JSON.stringify({ token }),
body: JSON.stringify(payload),
headers: {
'ApiSecret': 'myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4',
'Content-Type': 'application/json'
Expand All @@ -124,7 +124,7 @@ const response = await fetch(apiUrl + '/signin/verify', {
</template>
</CodeSwitcher>

The Passwordless.dev private API will unpack the verification token to check its legitimacy.
The Passwordless.dev private API will unpack the authentication token to check its legitimacy.

### Response

Expand All @@ -148,6 +148,60 @@ If successful, the `/signin/verify` endpoint will return a success response obje

Use the `.success` value (`true` or `false`) to determine next actions, i.e. whether to complete the sign-in ([learn more](frontend/javascript.md#signinwith)).

## /signin/generate-token

### Request

`POST` requests made to the `/signin/generate-token` endpoint create a [manually generated authentication token](concepts.md#tokens) for a user, side-stepping the regular sign-in flow (i.e. the `.signinWith*()` methods). The resulting token can then be verified through the `/signin/verify` endpoint and used just like a regular authentication token.

<CodeSwitcher :languages="{http:'HTTP',js:'JavaScript'}">
<template v-slot:http>

```http
POST https://v4.passwordless.dev/signin/generate-token HTTP/1.1
ApiSecret: myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4
Content-Type: application/json
{
"userId": "123"
}
```

</template>
<template v-slot:js>

```js
const apiUrl = 'https://v4.passwordless.dev';

// Generate an authentication token, side-stepping the usual signin process.
const payload = {
userId: '107fb578-9559-4540-a0e2-f82ad78852f7'
};

// POST the user ID to the Passwordless.dev API using your API private secret.
const response = await fetch(apiUrl + '/signin/generate-token', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'ApiSecret': 'myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4',
'Content-Type': 'application/json'
}
});
```

</template>
</CodeSwitcher>

### Response

If successful, the `/signin/generate-token` endpoint will return a response object, for example:

```json
{
"token": "d5vzCkL_GvpS4VYtoT3..."
}
```

## /alias

### Request
Expand All @@ -164,7 +218,14 @@ POST https://v4.passwordless.dev/alias HTTP/1.1
ApiSecret: myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4
Content-Type: application/json
{ "userId": "107fb578-9559-4540-a0e2-f82ad78852f7", "aliases": ["[email protected]", "[email protected]"], "hashing": true }
{
"userId": "107fb578-9559-4540-a0e2-f82ad78852f7",
"aliases": [
"[email protected]",
"[email protected]"
],
"hashing": true
}
```

</template>
Expand Down Expand Up @@ -253,25 +314,24 @@ If successful, the `/credentials/list` endpoint will return an array of `.json`

```json
[
{
"descriptor": {
"type": "public-key",
"id": "2mgrJ6LPItfxbnVc2UgFPHowNGKaYBm3Pf4so1bsXSk"
},
"publicKey": "pQECAyYgASFYIPi4M0A+ZFeyOHEC9iMe6dVhFnmOZdgac3MRmfqVpZ0AIlggWZ+l6+5rOGckXAsJ8i+mvPm4YuRQYDTHiJhIauagX4Q=",
"userHandle": "YzhhMzJlNWItNDZkMy00ODA4LWFlMTAtMTZkM2UyNmZmNmY5",
"signatureCounter": 0,
"createdAt": "2023-04-21T13:33:50.0764103",
"aaGuid": "adce0002-35bc-c60a-648b-0b25f1f05503",
"lastUsedAt": "2023-04-21T13:33:50.0764103",
"rpid": "myapp.example.com",
"origin": "https://myapp.example.com",
"country": "US",
"device": "Chrome, Mac OS X 10",
"nickname": "Fred's Macbook Pro 2",
"userId": "c8a32e5b-46d3-4808-ae10-16d3e26ff6f9"
{
"descriptor": {
"type": "public-key",
"id": "2mgrJ6LPItfxbnVc2UgFPHowNGKaYBm3Pf4so1bsXSk"
},
...
"publicKey": "pQECAyYgASFYIPi4M0A+ZFeyOHEC9iMe6dVhFnmOZdgac3MRmfqVpZ0AIlggWZ+l6+5rOGckXAsJ8i+mvPm4YuRQYDTHiJhIauagX4Q=",
"userHandle": "YzhhMzJlNWItNDZkMy00ODA4LWFlMTAtMTZkM2UyNmZmNmY5",
"signatureCounter": 0,
"createdAt": "2023-04-21T13:33:50.0764103",
"aaGuid": "adce0002-35bc-c60a-648b-0b25f1f05503",
"lastUsedAt": "2023-04-21T13:33:50.0764103",
"rpid": "myapp.example.com",
"origin": "https://myapp.example.com",
"country": "US",
"device": "Chrome, Mac OS X 10",
"nickname": "Fred's Macbook Pro 2",
"userId": "c8a32e5b-46d3-4808-ae10-16d3e26ff6f9"
} //, ...
]
```

Expand All @@ -289,7 +349,7 @@ ApiSecret: myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4
Content-Type: application/json
{
"credentialId":"qgB2ZetBhi0rIcaQK8_HrLQzXXfwKia46_PNjUC2L_w"
"credentialId": "qgB2ZetBhi0rIcaQK8_HrLQzXXfwKia46_PNjUC2L_w"
}
```

Expand Down
6 changes: 5 additions & 1 deletion src/guide/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ A credential represents a FIDO2 authenticator that is registered by Passwordless
In the regular course of business, Passwordless.dev uses two important types of ephemeral tokens:

- A **registration token**, created by the private API from requests to the `/register/token` endpoint ([learn more](api.md#register-token)). Your frontend will register this token with the end-user's device for use in sign-in operations.
- A **verification token**, created by the public API from calls to the `.signin()` method ([learn more](frontend/javascript.md#signinwith)). Your backend will verify this token to complete a sign-in operation
- An **authentication token**, created by the public API from calls to the `.signin()` method ([learn more](frontend/javascript.md#signinwith)). Your backend will verify this token to complete a sign-in operation (via the `/signin/verify` endpoint).

Additionally, Passwordless.dev uses other types of tokens for special purposes:

- A **manually generated authentication token**, created by the private API from requests to the `/signin/generate-token` endpoint. This token carries the same weight as a regular authentication token, but is generated manually, side-stepping the usual authentication flow. It's primarily used to facilitate account recovery and sign-in via magic links.

## More terms

Expand Down
2 changes: 1 addition & 1 deletion src/guide/frontend/aspnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ Regarding the login page, `/Account/Login`, clicking the 'Login' button will onc

There are two approaches you can take. You can either request an "alias" to verify which passkeys correspond to the alias, or if you have discoverable credentials, an input form may not be necessary.

The process of logging in differs from registration. During login, you will request valid passkeys from your authenticator to obtain a verification token. Subsequently, this verification token will be transmitted to your backend to initiate the session.
The process of logging in differs from registration. During login, you will request valid passkeys from your authenticator to obtain an authentication token. Subsequently, this authentication token will be transmitted to your backend to initiate the session.

With the "Passwordless ASP.NET Identity SDK," you can streamline this process by making a simple call to POST /passwordless-login, and the SDK will handle all the necessary steps for you.

Expand Down
4 changes: 2 additions & 2 deletions src/guide/frontend/javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Successful implementation will prompt Passwordless.dev to negotiate creation of

## .signinWith()

Call the `.signin` methods to generate a [verification token](../concepts.md#tokens) that will be checked by your backend to complete a sign-in. There are a few different `.signinWith*()` methods available:
Call the `.signin` methods to generate an [authentication token](../concepts.md#tokens) that will be checked by your backend to complete a sign-in. There are a few different `.signinWith*()` methods available:

| Method | Description | Example |
| --------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------- |
Expand All @@ -113,7 +113,7 @@ const p = new Passwordless.Client({
apiKey: 'myapplication:public:4364b1a49a404b38b843fe3697b803c8'
});

// Generate a verification token for the user.
// Generate an authentication token for the user.

// Option 1: Enable browsers to suggest passkeys for any input that has autofill="webauthn" (only works with discoverable passkeys).
const { token, error } = await p.signinWithAutofill();
Expand Down
12 changes: 6 additions & 6 deletions src/guide/get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ Next, implement a workflow on your backend and frontend for signing in with a [p

Code that you write must:

1. On your frontend, initiate your sign-in and retrieve a [verification token](concepts.md#tokens) that will be checked by your backend to complete a sign-in. To initiate the sign-in, you can use an alias, userId, or Discoverable Credential ([learn more](frontend/javascript.md#signinwith)), for example:
1. On your frontend, initiate your sign-in and retrieve an [authentication token](concepts.md#tokens) that will be checked by your backend to complete a sign-in. To initiate the sign-in, you can use an alias, userId, or Discoverable Credential ([learn more](frontend/javascript.md#signinwith)), for example:

<Badge text="frontend" type="tip"/>

Expand All @@ -200,7 +200,7 @@ const p = new Client({
// Allow the user to specify a username or alias.
const alias = '[email protected]';

// Generate a verification token for the user.
// Generate an authentication token for the user.
const { token, error } = await p.signinWithAlias(alias);
// Tip: You can also try p.signinWithDiscoverable();

Expand All @@ -212,19 +212,19 @@ if (verifiedUser.success === true) {
}
```

Successful implementation will make a verification token available to the backend. In the above example, the client waits for the backend to return `true` (**step 2**) before proceeding to act on the confirmed sign-in.
Successful implementation will make an authentication token available to the backend. In the above example, the client waits for the backend to return `true` (**step 2**) before proceeding to act on the confirmed sign-in.

2. Validate the verification token by calling the Passwordless.dev API's `/signin/verify` endpoint ([learn more](api.md#signin-verify)) with generated token, for example:
2. Validate the authentication token by calling the Passwordless.dev API's `/signin/verify` endpoint ([learn more](api.md#signin-verify)) with generated token, for example:

<Badge text="backend" type="warning"/>

```js
// Code written for this step should run on your backend.

// Fetch the verification token from your frontend.
// Fetch the authentication token from your frontend.
const token = { token: req.query.token };

// POST the verification token to the Passwordless.dev API using your API private secret.
// POST the authentication token to the Passwordless.dev API using your API private secret.
const apiUrl = 'https://v4.passwordless.dev';
const response = await fetch(apiurl + '/signin/verify', {
method: 'POST',
Expand Down
12 changes: 10 additions & 2 deletions src/guide/self-hosting.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ storing the generated configuration file and database. Otherwise, the database a
To get up and running, execute the lines below.

```bash
docker pull ghcr.io/passwordless/passwordless-self-host
docker pull bitwarden/passwordless-self-host:stable
docker run \
--publish 5701:5701 \
--volume {your-host-directory}:/etc/bitwarden_passwordless \
ghcr.io/passwordless/passwordless-self-host
bitwarden/passwordless-self-host:stable
```

You should now be able to access your own `Passwordless.dev` instance at:
Expand Down Expand Up @@ -68,6 +68,14 @@ For Api:
docker exec -it {name-of-container} cat /app/Api/mail.md
```

## Available Tags

- `stable` - built from the latest stable version release (recommended)
- `1.0.55` - built from a specific stable version release
- `latest` - built from the current state of the `main` branch

For more information, please see the [Docker Hub](https://hub.docker.com/r/bitwarden/passwordless-self-host/tags) page.

## Known Issues

- There is no active sync between self-hosted Admin Console and the cloud hosted [Admin Console](https://admin.passwordless.dev).
Expand Down
4 changes: 2 additions & 2 deletions src/guide/self-hosting/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Failure to mount persistent storage, will:
$ docker run -d \
--name passwordless \
--mount source=/your/persistent/storage,target=/etc/bitwarden_passwordless \
ghcr.io/passwordless/passwordless-self-host:latest
bitwarden/passwordless-self-host:stable
```

## Database
Expand Down Expand Up @@ -142,5 +142,5 @@ If the following keys do not exist, they will be generated automatically:
- PasswordlessManagement::ManagementKey
- SALT_KEY

It is recommended that you have them generated automatically, the first time you run `ghcr.io/passwordless/passwordless-self-host`.
It is recommended that you have them generated automatically, the first time you run `bitwarden/passwordless-self-host`.
```
12 changes: 6 additions & 6 deletions src/guide/self-hosting/running-locally.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
- No permanent storage: In this example, the generated `config.json` and `Sqlite databases` will be lost.

```bash
docker pull ghcr.io/passwordless/passwordless-self-host
docker pull bitwarden/passwordless-self-host:stable
docker run \
--publish 5042:5701 \
--env BWP_ENABLE_SSL=true \
ghcr.io/passwordless/passwordless-self-host
bitwarden/passwordless-self-host:stable
```

## Simple example #2
Expand All @@ -19,12 +19,12 @@ docker run \
- Permanent storage: In this example, the generated `config.json` and `Sqlite databases` will be retained on the host in directory `/your/directory`.

```bash
docker pull ghcr.io/passwordless/passwordless-self-host
docker pull bitwarden/passwordless-self-host:stable
docker run \
--publish 5042:5701 \
--volume /your/directory:/etc/bitwarden_passwordless \
--env BWP_PORT=5042 \
ghcr.io/passwordless/passwordless-self-host
bitwarden/passwordless-self-host:stable
```

## Example with SSL
Expand All @@ -33,13 +33,13 @@ docker run \
- Permanent storage: In this example, the generated `config.json` and `Sqlite databases` will be retained on the host in directory `/your/directory`.

```bash
docker pull ghcr.io/passwordless/passwordless-self-host
docker pull bitwarden/passwordless-self-host:stable
docker run \
--publish 5042:5701 \
--volume /your/directory:/etc/bitwarden_passwordless \
--env BWP_PORT=5042 \
--env BWP_ENABLE_SSL=true \
ghcr.io/passwordless/passwordless-self-host
bitwarden/passwordless-self-host:stable
```

:::warning
Expand Down

0 comments on commit 4aadb8b

Please sign in to comment.