Access Control
Authentication
Web authentication is handled as part of the framework; we pass authentication results down as a locals
object, giving
you control over how to use them throughout the lifecycle of a request.
export async function load({ locals }) {
const authResult = locals.authResult;
if (authResult.success) {
log.debug("User is authenticated");
return {
user: authResult.claims,
};
} else {
log.debug("User is not authenticated, but since this is a public route, we allow the user anyway");
}
}
You may simply access the locals.authResult
object in your layouts or pages to determine if a user is authenticated.
It also contains all claims from the JWT, allowing you to perform any additional checks and guards you want in your
pages or layouts.
The AuthResult
Object
The AuthResult type can represent two possible outcomes: AuthResultSuccess
and AuthResultFail
.
type AuthResult = AuthResultSuccess | AuthResultFail;
type AuthResultSuccess = {
success: true;
claims: AuthClaims;
access_token?: string;
};
type AuthResultFail = {
success: false;
};
AuthResultSuccess
AuthResultSuccess indicates a successful authentication and provides:
- A boolean
success
field that is always true, representing a successful authentication. - The user claims decoded from the access token (as provided by Keycloak).
- The original access token itself, that can be used to make API requests to other backend services.
AuthResultFail
AuthResultFail indicates a failed authentication and contains a boolean success
field that is always set to false,
representing a failed authentication
This typing is to allow type narrowing to remind developers that claims
and access_token
are only available when
the user is authenticated.
Guarding Routes
Simple Authentication-Based Protection
As the resulting authentication information is made available to your application through the locals object. It can be checked through the layout, pages, or even passed all the way to the browser to allow you to add conditional rendering logic (e.g., displaying user names, showing/hiding content based on login status, etc).
export const GET: RequestHandler = async ({ locals, fetch, url }) => {
// Access the user id from the authentication result.
const user_id: string = locals.authResult.claims.sub;
// Construct headers and passing the access token into the header using the result.
const headers: HeaderInit = {
Authentication: "Bearer" + locals.authResult.access_token,
};
// Call api...
const response = await fetch(url, {
headers,
});
};
Permission-based Protection
You can perform more than just simple successful / unsuccessful authentication guards, for example, you might want to enforce role-based access control directly within your API route handlers (which you can do so by checking the claims, as the role information is available there), or even make an API call to the IAMS-AAS service to check if the user is authorized to access a specific resource.
The following sample is how you might want to guard access to a specific page based on a user's permissions:
import type { PageServerLoad } from "./$types";
import { redirect } from "@sveltejs/kit";
const IAMS_AAS_URL = `http://iams-aas.example.com`;
export const load: PageServerLoad = async ({ fetch, locals }) => {
// Guard to redirect user on authentication failure
if (!locals.authResult.success) {
redirect(307, "/example_unauthorized_page");
}
const tenant_id = locals.authResult.claims.tenant_id;
const user_id = locals.authResult.claims.user_id;
const resource_name = "example_resource";
const scope_name = "example_scope";
// IAMS_AAS policy evaluation endpoint to determine if
// this user has access to a specific resource
const url = `${IAMS_AAS_URL}/admin/tenants/\
${tenant_id}/users/\
${user_id}/resources-by-name/\
${resource_name}/scopes-by-name/\
${scope_name}/evaluate`;
const response = await fetch(url, {
headers: {
Authorization: `Bearer example_nonsense_token`,
},
});
const result = await response.json();
// Guard to redirect user on authorization failure (permission denied)
if (result !== "PERMIT") {
redirect(307, "/example_unauthorized_page");
}
return {};
};
The same pattern can be applied to non-page (API) routes.
For more details on how to add find grained access control via permission-based guards, refer to the Fine-Grained Access Control documentation.