Skip to content

Commit

Permalink
feat: add AUTH_WEBAUTHN_RP_ID environment variable (#446)
Browse files Browse the repository at this point in the history
* feat: add AUTH_WEBAUTHN_RP_ID environment variable

* test(webauthn): add test when rpId set in environment variables

* chore: add changeset

* chore: update AUTH_WEBAUTHN_RP_ID description

* fix: typo in `AUTH_WEBAUTHN_RP_ID` description
  • Loading branch information
onehassan authored Nov 28, 2023
1 parent 2e3096c commit 634f2bf
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/soft-brooms-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'hasura-auth': minor
---

feat: add `AUTH_WEBAUTHN_RP_ID` environment variable
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ AUTH_PROVIDER_STRAVA_CLIENT_SECRET=
# WEBAUTHN
AUTH_WEBAUTHN_ENABLED=
AUTH_WEBAUTHN_RP_NAME='Nhost App'
AUTH_WEBAUTHN_RP_ID='nhost.io'
AUTH_WEBAUTHN_RP_ORIGINS=

# LOGS
Expand Down
1 change: 1 addition & 0 deletions docs/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
| AUTH_JWT_CUSTOM_CLAIMS | | |
| AUTH_WEBAUTHN_ENABLED | When enabled, passwordless Webauthn authentication can be done via device supported strong authenticators like fingerprint, Face ID, etc. | false |
| AUTH_WEBAUTHN_RP_NAME | Relying party name. Friendly name visual to the user informing who requires the authentication. Probably your app's name. | |
| AUTH_WEBAUTHN_RP_ID | Relying party id. If not set `AUTH_CLIENT_URL` will be used as a default. | |
| AUTH_WEBAUTHN_RP_ORIGINS | Array of URLs where the registration is permitted and should have occurred on. `AUTH_CLIENT_URL` will be automatically added to the list of origins if is set. | |
| AUTH_WEBAUTHN_ATTESTATION_TIMEOUT | How long (in ms) the user can take to complete authentication. | `60000` (1 minute) |

Expand Down
3 changes: 3 additions & 0 deletions src/utils/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ export const ENV = {
get AUTH_WEBAUTHN_RP_NAME() {
return castStringEnv('AUTH_WEBAUTHN_RP_NAME', '');
},
get AUTH_WEBAUTHN_RP_ID() {
return castStringEnv('AUTH_WEBAUTHN_RP_ID', '');
},
get AUTH_WEBAUTHN_RP_ORIGINS() {
const origins = castStringArrayEnv('AUTH_WEBAUTHN_RP_ORIGINS', []);
const clientUrl = ENV.AUTH_CLIENT_URL;
Expand Down
9 changes: 7 additions & 2 deletions src/utils/webauthn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ import { ENV } from './env';
import { gqlSdk } from './gql-sdk';
import { AuthUserSecurityKeys_Insert_Input } from './__generated__/graphql-request';

export const getWebAuthnRelyingParty = () =>
ENV.AUTH_CLIENT_URL && new URL(ENV.AUTH_CLIENT_URL).hostname;
export const getWebAuthnRelyingParty = () => {
if (ENV.AUTH_WEBAUTHN_RP_ID) {
return ENV.AUTH_WEBAUTHN_RP_ID;
}

return ENV.AUTH_CLIENT_URL && new URL(ENV.AUTH_CLIENT_URL).hostname;
};

export const getCurrentChallenge = async (id: string) => {
const { user } = await gqlSdk.getUserChallenge({ id });
Expand Down
34 changes: 34 additions & 0 deletions test/routes/signin/webauthn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,40 @@ describe('webauthn', () => {
});
});

it('should return authentication options with rpId set in the environement variables', async () => {
const email = faker.internet.email();
const password = faker.internet.password();

const record = await insertDbUser(client, email, password, true, false);
expect(record.rowCount).toEqual(1);

const userRecord = await client.query(`SELECT id FROM auth.users LIMIT 1;`);
expect(userRecord.rows).toBeArrayOfSize(1);
expect(userRecord.rows[0]).toHaveProperty('id');

const rpId = 'example.io';

await request.post('/change-env').send({
AUTH_WEBAUTHN_RP_ID: rpId,
});

const { body } = await request
.post('/signin/webauthn')
.send({ email })
.expect(StatusCodes.OK);

// checking its persist and remove it as cannot compare
expect(body).toHaveProperty('challenge');
delete body.challenge;

expect(body).toEqual({
allowCredentials: [],
rpId,
timeout: 60000,
userVerification: 'preferred',
});
});

it('should fail verify user is webauth is not enabled', async () => {
const email = faker.internet.email();

Expand Down

0 comments on commit 634f2bf

Please sign in to comment.