./src/routes/AmplifyInit.svelte automatically loads ./amplify_outputs.json generated by Amplify CLI on build time or sandbox mode. ./amplify_outputs.json should not be modified manually and so it is .gitignored.
Server Side Rendering (SSR) works good but streaming does not work.
SvelteKit is a full-stack framework based on Svelte frontend library. SvelteKit supports server-side rendering (SSR). Next.js is in this field but I prefer SvelteKit because we can write very simple and efficient codes in SvelteKit, it's great.
AWS Amplify is service to build and deploy web application with some AWS services such as Cognito/Lambda/DynamoDB/S3 or so without deep knowledge about them.
In these days Amplify supports SSR and there are some examples to deploy SvelteKit with Amplify.
It is nice we can deploy SvelteKit application only by connecting GitHub repo to Amplify. One point, we should note that SSR "Streaming" is not supported yet.
Actually, I'm not familiar with Amplify "Gen1". I talk about Gen2 in entrie this article.
Amplify Gen2 omits CLI command to add Amplify Backends(auth, data...). Instead of CLI, you can declaratively specify backends by codes in TypeScript and Gen2 provides us with "sandbox" feature, it enables us to launch backends only for your development, this is similar to "branching" in Supabase but it is interesting that Amplify make sandboxes for local development.
Traditionally, you can access Amplify Auth(Cognito) from frontend only with following codes:
// initializationimport{Amplify}from'aws-amplify';importoutputsfrom'./amplify_outputs.json';// generated by Amplify CLIAmplify.configure(outputs);// signinimport{signIn}from'aws-amplify/auth'awaitsignIn({username:"hello@mycompany.com",password:"hunter2",})// credentials stored in LocalStorage// ...perform authorized actions for backends with credentials
This approach have been standard in Amplify but in context of SSR we need better approach than this. Assuming we have public pages and private pages. Is SSR, server should return private pages only for authenticated users. To adjust authentication processes for SSR, we need to:
send credentials from client to server
verify credentials
navigate only verified users to private pages
Adapter for Next.js
For Next.js, an "adapter" is officially provided by Amplify.
It is not for SvelteKit. Then I tried to write some codes.
Adapter for SvelteKit
The procedure to serve pages in SvelteKit is similar to in Next.js. I wrote adapter for SvelteKit quoting some codes of adapter-nextjs. The following is parts of them:
{ ssr: true } means to use cookie for storing credentials instead of LocalStorage. Once signed in, credentials are wrote to cookie and they are sent to server on accessing any pages.
Response Hooks
// src/hooks.server.tsimport{redirect,typeHandle}from'@sveltejs/kit';import{fetchAuthSession}from'aws-amplify/auth/server';import{createRunWithAmplifyServerContext}from'$lib/adapter-sveltekit';importoutputsfrom'../amplify_outputs.json';// init auth-checker with outputs once when the server startsconstrunWithAmplifyServerContext=createRunWithAmplifyServerContext(outputs);exportconsthandle:Handle=async ({event,resolve}):Promise<Response>=>{if (!event.url.pathname.startsWith('/private')){returnresolve(event);}constauthenticated=awaitrunWithAmplifyServerContext({event,operation:async (contextSpec)=>{try{constsession=awaitfetchAuthSession(contextSpec);returnsession.tokens?.accessToken!==undefined&&session.tokens?.idToken!==undefined;}catch (error){console.log(error);returnfalse;}}});if (!authenticated){redirect(303,'/');}else{returnresolve(event);}};
handle() in hooks.server.ts is called on before every response. Only verified users can access pages under /private routes.
Accept RequestEvent in SvelteKit instead of "Context" in Next.js
Workaround for signOut
aws-amplify/auth provides signOut() but this doesn't work for SSR mode, it might discard only LocalStorage. The cookies wrote by Amplify seems to have "HttpOnly" so we have to revoke cookies from server.
// src/routes/signin/+page.server.tsexportconstactions={signOut:async ({cookies})=>{// remove all cookies startsWith "CognitoIdentityServiceProvider"constcognitoCookies=cookies.getAll().filter((cookie)=>cookie.name.startsWith('CognitoIdentityServiceProvider'));for (constcookieofcognitoCookies){cookies.set(cookie.name,'',{maxAge:0,path:'/'});}}};
This is a good case to use form action in SvelteKit. By sending POST request via form and invoke an action named as "signOut", server overwrites the cookie as "expired". We can find cookies of Amplify by checking prefix "CognitoIdentityServiceProvider".
Perfect! You can authenticate users in SSR context in SvelteKit!.
Conclusion
I shown that SvelteKit can be used in Amplify, with SSR authentication. SvelteKit is the great framework and I hope that Amplify, which deploy applications easily, can support SvelteKit more.