Skip to content

Commit

Permalink
feat(console): client-side session managment for webauthn
Browse files Browse the repository at this point in the history
  • Loading branch information
xmlking committed Jun 27, 2024
1 parent cc37494 commit b1db9ee
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 31 deletions.
9 changes: 5 additions & 4 deletions apps/console/src/lib/server/utils/nhost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ export async function getServerNhost(initialSession: NhostSession | undefined, c
* @param {NhostSession} session - The session to set in the cookie
*/
export function setNhostSessionInCookies(cookies: Cookies, session: NhostSession) {
const expires = new Date();
// Expire the cookie 60 seconds before the token expires
expires.setSeconds(expires.getSeconds() + session.accessTokenExpiresIn - 60);
// const expires = new Date();
// expires.setSeconds(expires.getSeconds() + session.accessTokenExpiresIn - 60);
cookies.set(NHOST_SESSION_KEY, btoa(JSON.stringify(session)), {
path: '/',
sameSite: 'strict',
httpOnly: true,
expires,
// make it as session cookie and let the browser refresh and update cookie
httpOnly: false,
// expires,
});
}
55 changes: 34 additions & 21 deletions apps/console/src/lib/stores/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { hasSecurityKey } from '$lib/nhost';
import type { User } from '@nhost/nhost-js';
import { NhostClient } from '@nhost/nhost-js';
import { Logger } from '@spectacular/utils';
import Cookies from 'js-cookie';
import { derived, get, readable, readonly, writable } from 'svelte/store';

const log = new Logger('user.store.client');
Expand All @@ -17,6 +18,7 @@ export const nhost = new NhostClient({
graphqlUrl: env.PUBLIC_NHOST_GRAPHQL_URL,
storageUrl: env.PUBLIC_NHOST_STORAGE_URL,
functionsUrl: env.PUBLIC_NHOST_FUNCTIONS_URL,
start: browser
});

/**
Expand All @@ -30,33 +32,44 @@ export const user = readonly(_user);
* Readable: updates every time the authentication status changes from signed-in to signed-out.
*/
export const isAuthenticated = readable<boolean>(false, (set) => {
set(nhost.auth.isAuthenticated());
nhost.auth.onAuthStateChanged((event, session) => {
log.debug(`The auth state has changed. State is now ${event} with session:`, { session });
switch (event) {
case 'SIGNED_IN':
set(true);
_user.set(session?.user || null);
break;
case 'SIGNED_OUT':
set(false);
_user.set(null);
break;
}
});
return () => log.debug('no more subscribers for isAuthenticated');
if (browser) {
set(nhost.auth.isAuthenticated());
nhost.auth.onAuthStateChanged((event, session) => {
log.debug(`The auth state has changed. State is now ${event} with session:`, { session });
switch (event) {
case 'SIGNED_IN':
set(true);
_user.set(session?.user || null);
break;
case 'SIGNED_OUT':
set(false);
_user.set(null);
Cookies.remove(NHOST_SESSION_KEY);
break;
}
});
return () => log.debug('no more subscribers for isAuthenticated');
}
});

/**
* Readable: updates every time the access or refresh token is changed.
*/
export const accessToken = readable<string | null>(null, (set) => {
set(nhost.auth.getAccessToken() ?? null);
nhost.auth.onTokenChanged((session) => {
log.debug('The access token refreshed:', { session });
set(session?.accessToken ?? null);
});
return () => log.debug('no more subscribers for accessToken');
if (browser) {
set(nhost.auth.getAccessToken() ?? null);
nhost.auth.onTokenChanged((session) => {
log.debug('The access token refreshed:', { session });
set(session?.accessToken ?? null);
// save session as cookie everytime token is refreshed or user signin via WebAuthN
Cookies.set(NHOST_SESSION_KEY, btoa(JSON.stringify(session)), {
path: '/',
sameSite: 'strict',
secure: true,
});
});
return () => log.debug('no more subscribers for accessToken');
}
});

/**
Expand Down
9 changes: 3 additions & 6 deletions apps/console/src/routes/(auth)/signin/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { getToastStore } from '@skeletonlabs/skeleton';
import { DebugShell } from '@spectacular/skeleton/components';
import { Icon } from '@spectacular/skeleton/components/icons';
import { Logger } from '@spectacular/utils';
import Cookies from 'js-cookie';
// import { SiGithub } from "@icons-pack/svelte-simple-icons";
import { AlertTriangle, Fingerprint, Github, Loader, Mail, MoreHorizontal } from 'lucide-svelte';
import { fade } from 'svelte/transition';
Expand Down Expand Up @@ -95,13 +94,11 @@ async function waSignin() {
if (!$pwErrors.email) {
const { session, error: signInError } = await nhost.auth.signIn({ email: $pwlForm.email, securityKey: true });
if (session) {
Cookies.set(NHOST_SESSION_KEY, btoa(JSON.stringify(session)), {
path: '/',
sameSite: 'strict',
});
goto('/dashboard');
handleMessage({ type: 'success', message: 'Signin sucessfull 😎' } as const, toastStore);
} else {
console.log(signInError);
log.error(signInError);
handleMessage({ type: 'error', message: `Signin failed: ${signInError?.message}` } as const, toastStore);
}
}
}
Expand Down

0 comments on commit b1db9ee

Please sign in to comment.