Skip to content

Commit

Permalink
feat: SessionAuth SSR support (initialSessionAuthContext) (#789)
Browse files Browse the repository at this point in the history
* feat: Add SSR support for SessionAuth (initialSessionAuthContext)

* Add preloaded to sessionAuth test file

* Rename preloaded to isContextFromSSR

* changes to SSRSessionContextType

* add missing initialSessionAuthContext test
  • Loading branch information
sasha240100 authored Jan 26, 2024
1 parent d2ca50e commit f99aef2
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 19 deletions.
21 changes: 16 additions & 5 deletions lib/build/index2.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions lib/build/recipe/session/sessionAuth.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions lib/build/recipe/session/types.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion lib/ts/recipe/session/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { RecipeComponentsOverrideContextProvider } from "./componentOverrideCont
import Session from "./recipe";
import SessionAuthWrapper from "./sessionAuth";
import SessionContext from "./sessionContext";
import { InputType, SessionContextType } from "./types";
import { InputType, SessionContextType, SSRSessionContextType } from "./types";
import { useClaimValue as useClaimValueFunc } from "./useClaimValue";
import useSessionContextFunc from "./useSessionContext";

Expand Down Expand Up @@ -150,6 +150,7 @@ export {
InputType,
SessionContext,
SessionContextType,
SSRSessionContextType,
BooleanClaim,
ClaimValidationError,
ClaimValidationResult,
Expand Down
38 changes: 32 additions & 6 deletions lib/ts/recipe/session/sessionAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,21 @@ import Session from "./recipe";
import SessionContext from "./sessionContext";
import { getFailureRedirectionInfo } from "./utils";

import type { LoadedSessionContext, RecipeEventWithSessionContext, SessionContextType } from "./types";
import type {
LoadedSessionContext,
RecipeEventWithSessionContext,
SessionContextType,
SSRSessionContextType,
} from "./types";
import type { Navigate, ReactComponentClass, SessionClaimValidator, UserContext } from "../../types";
import type { PropsWithChildren } from "react";
import type { ClaimValidationError } from "supertokens-web-js/recipe/session";

export type SessionAuthProps = {
/**
* Initial context that is rendered on a server side (SSR).
*/
initialSessionAuthContext?: SSRSessionContextType;
/**
* For a detailed explanation please see https://github.com/supertokens/supertokens-auth-react/issues/570
*/
Expand Down Expand Up @@ -65,9 +74,16 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
);
}

const initialContext: SessionContextType = props.initialSessionAuthContext
? {
...props.initialSessionAuthContext,
invalidClaims: [], // invalidClaims is currently unsupported on server (SSR)
}
: { loading: true };

// Reusing the parent context was removed because it caused a redirect loop in an edge case
// because it'd also reuse the invalid claims part until it loaded.
const [context, setContext] = useState<SessionContextType>({ loading: true });
const [context, setContext] = useState<SessionContextType>(initialContext);

const session = useRef<Session>();

Expand Down Expand Up @@ -101,6 +117,7 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,

if (sessionExists === false) {
return {
isContextFromSSR: false,
loading: false,
doesSessionExist: false,
accessTokenPayload: {},
Expand Down Expand Up @@ -128,6 +145,7 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
throw err;
}
return {
isContextFromSSR: false,
loading: false,
doesSessionExist: false,
accessTokenPayload: {},
Expand All @@ -138,6 +156,7 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,

try {
return {
isContextFromSSR: false,
loading: false,
doesSessionExist: true,
invalidClaims,
Expand All @@ -159,6 +178,7 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
// This means that loading the access token or the userId failed
// This may happen if the server cleared the error since the validation was done which should be extremely rare
return {
isContextFromSSR: false,
loading: false,
doesSessionExist: false,
accessTokenPayload: {},
Expand Down Expand Up @@ -246,7 +266,12 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
userContext,
});
if (failureRedirectInfo.redirectPath) {
setContext({ ...event.sessionContext, loading: false, invalidClaims });
setContext({
...event.sessionContext,
isContextFromSSR: false,
loading: false,
invalidClaims,
});
return await SuperTokens.getInstanceOrThrow().redirectToUrl(
failureRedirectInfo.redirectPath,
navigate
Expand All @@ -259,21 +284,22 @@ const SessionAuth: React.FC<PropsWithChildren<SessionAuthProps>> = ({ children,
});
return setContext({
...event.sessionContext,
isContextFromSSR: false,
loading: false,
invalidClaims,
accessDeniedValidatorError: failureRedirectInfo.failedClaim,
});
}
}
setContext({ ...event.sessionContext, loading: false, invalidClaims });
setContext({ ...event.sessionContext, isContextFromSSR: false, loading: false, invalidClaims });

return;
}
case "SIGN_OUT":
setContext({ ...event.sessionContext, loading: false, invalidClaims: [] });
setContext({ ...event.sessionContext, isContextFromSSR: false, loading: false, invalidClaims: [] });
return;
case "UNAUTHORISED":
setContext({ ...event.sessionContext, loading: false, invalidClaims: [] });
setContext({ ...event.sessionContext, isContextFromSSR: false, loading: false, invalidClaims: [] });
if (props.onSessionExpired !== undefined) {
props.onSessionExpired();
} else if (props.requireAuth !== false && props.doRedirection !== false) {
Expand Down
3 changes: 3 additions & 0 deletions lib/ts/recipe/session/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export type SessionContextUpdate = {
};

export type LoadedSessionContext = {
isContextFromSSR: boolean;
loading: false;
invalidClaims: ClaimValidationError[];
accessDeniedValidatorError?: ClaimValidationError;
Expand All @@ -61,6 +62,8 @@ export type SessionContextType =
loading: true;
};

export type SSRSessionContextType = Omit<LoadedSessionContext, "invalidClaims" | "accessDeniedValidatorError">;

export type AccessDeniedThemeProps = {
recipe: Session;
navigate: Navigate;
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions recipe/session/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* under the License.
*/
"use strict";
"use client"; // Important for NextJS support (SessionAuth is a client component)
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Expand Down
1 change: 1 addition & 0 deletions test/unit/componentOverrides.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ describe("Components override per recipe provider", () => {
],
});
setMockResolvesSession({
isContextFromSSR: false,
userId: "mock-user-id",
accessTokenPayload: {},
invalidClaims: [],
Expand Down
1 change: 1 addition & 0 deletions test/unit/recipe/emailpassword/signInUp.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ describe("EmailPassword.SignInAndUp", () => {
});

setMockResolvesSession({
isContextFromSSR: false,
userId: "mock-user-id",
accessTokenPayload: {},
invalidClaims: [],
Expand Down
1 change: 1 addition & 0 deletions test/unit/recipe/passwordless/signInUp.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ describe("Passwordless.SingInUp", () => {
});

setMockResolvesSession({
isContextFromSSR: false,
userId: "mock-user-id",
accessTokenPayload: {},
invalidClaims: [],
Expand Down
Loading

0 comments on commit f99aef2

Please sign in to comment.