Edit this page

Authentication

You can make information about the authenticated user available to your pages and UI components by defining a custom pageContext property, such as pageContext.user.

You can then access pageContext.user from any UI component using usePageContext() and +passToClient.

In principle, you can use Vike with any authentication tool such as:

With vike-server

You can use +onCreatePageContext.server.js:

// pages/+onCreatePageContext.server.js
// Environment: server
 
// On the server-side, this hook is called upon new incoming HTTP requests
export async function onCreatePageContext(pageContext) {
  // vike-server defines pageContext.runtime
  const { req } = pageContext.runtime
 
  // Authentication middlewares (e.g. Passport.js and Grant) usually provide
  // information about the logged-in user at req.user
  pageContext.user = req.user
 
  // Or when using a third-party authentication provider (e.g. Auth0)
  pageContext.user = await someAuthApi.getUser(req.headers)
}

You may also simply directly access pageContext.runtime.req.user instead.

Without vike-server

If you don't use vike-server, then you can use renderPage():

// server/index.js
 
// Vike server middleware
app.get('*', async (req, res) => {
  // Authentication middlewares (e.g. Passport.js and Grant) usually provide
  // information about the logged-in user at req.user
  const user = req.user
 
  // Or when using a third-party authentication provider (e.g. Auth0)
  const user = await someAuthApi.getUser(req.headers)
 
  const pageContextInit = {
    urlOriginal: req.url,
    // Make the user object available at pageContext.user
    user
  }
  const result = await renderPage(pageContextInit)
 
  /* ... */
})

SSG

SSG apps don't have a server and, therefore, a custom property such as pageContext.user cannot be defined on the server-side.

Instead, you can use +onCreateGlobalContext.client.js:

// pages/+onCreateGlobalContext.client.js
// Environment: client
 
export async function onCreateGlobalContext(globalContext) {
  // Fetch user information from your backend (or an authentication SaaS platform)
  const user = await fetchUseInfo()
  globalContext.user = user
}

You can then use pageContext.globalContext and/or getGlobalContext() to access globalContext.user anywhere.

Login flow

By using +guard with throw redirect() or throw render() you can:

  • Implement login flows.
  • Protect private pages from unprivileged access.
// /pages/admin/+guard.js
 
import { render, redirect } from 'vike/abort'
 
export const guard = (pageContext) => {
  const { user } = pageContext
  if (user === null) {
    // Render the login page while preserving the URL. (This is novel technique
    // which we explain down below.)
    throw render('/login')
    /* The more traditional way, redirect the user:
    throw redirect('/login')
    */
  }
  if (user.role !== 'admin') {
    // Render the error page and show message to the user
    throw render(403, 'Only admins are allowed to access this page.')
  }
}

Using render('/login') instead of redirect('/login') allows the URL to be preserved during the entire login flow:

  1. Unauthenticated user goes to URL /admin and sees the login page. (URL is /admin.)
  2. User fills the sign-in form and successfully logs in. (URL is still /admin.)
  3. Reload the page, the user now sees the admin page. (URL is still /admin.)

See example.

You can also define a guard() hook that applies to multiple pages:

// /pages/+guard.js
 
// This guard() hook applies to all pages: the file is located at /pages/+guard.js
// and therefore applies to all /pages/**/+Page.js
 
import { render } from 'vike/abort'
 
export const guard = (pageContext) => {
  if (!pageContext.user) {
    throw render('/login')
  }
}

See also