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 ofredirect('/login')
allows the URL to be preserved during the entire login flow:
- Unauthenticated user goes to URL
/admin
and sees the login page. (URL is/admin
.)- User fills the sign-in form and successfully logs in. (URL is still
/admin
.)- 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')
}
}