Skip to content

Commit

Permalink
feat(types,clerk-react,nextjs): Add loadOrg option for Next.js withSe…
Browse files Browse the repository at this point in the history
…rverSideAuth middleware
  • Loading branch information
igneel64 committed Jul 6, 2022
1 parent f6739f9 commit 0889bde
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 15 deletions.
1 change: 1 addition & 0 deletions packages/backend-core/src/util/createGetToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ export const createSignedOutState = () => {
user: null,
getToken: signedOutGetToken,
claims: null,
organization: null,
};
};
7 changes: 5 additions & 2 deletions packages/nextjs/src/middleware/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Session, User } from '@clerk/clerk-sdk-node';
import type { Organization, Session, User } from '@clerk/clerk-sdk-node';
import { ClerkJWTClaims, ServerSideAuth } from '@clerk/types';
import { GetServerSidePropsContext } from 'next';

Expand All @@ -8,6 +8,7 @@ export type Awaited<T> = T extends PromiseLike<infer U> ? U : T;
export type WithServerSideAuthOptions = {
loadUser?: boolean;
loadSession?: boolean;
loadOrg?: boolean;
jwtKey?: string;
authorizedParties?: string[];
};
Expand All @@ -23,6 +24,7 @@ export type AuthData = {
session: Session | undefined | null;
userId: string | null;
user: User | undefined | null;
organization: Organization | undefined | null;
getToken: (...args: any) => Promise<string | null>;
claims: ClerkJWTClaims | null;
};
Expand All @@ -34,4 +36,5 @@ export type ContextWithAuth<Options extends WithServerSideAuthOptions = any> = G
export type RequestWithAuth<Options extends WithServerSideAuthOptions = any> = GetServerSidePropsContext['req'] & {
auth: ServerSideAuth;
} & (Options extends { loadSession: true } ? { session: Session | null } : {}) &
(Options extends { loadUser: true } ? { user: User | null } : {});
(Options extends { loadUser: true } ? { user: User | null } : {}) &
(Options extends { loadOrg: true } ? { organization: Organization | null } : {});
10 changes: 6 additions & 4 deletions packages/nextjs/src/middleware/utils/getAuthData.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AuthStatus, createGetToken, createSignedOutState } from '@clerk/backend-core';
import Clerk, { sessions, users } from '@clerk/clerk-sdk-node';
import Clerk, { organizations, sessions, users } from '@clerk/clerk-sdk-node';
import { GetServerSidePropsContext } from 'next';

import { AuthData, WithServerSideAuthOptions } from '../types';
Expand All @@ -12,7 +12,7 @@ export async function getAuthData(
opts: WithServerSideAuthOptions = {},
): Promise<AuthData | null> {
const { headers, cookies } = ctx.req;
const { loadSession, loadUser, jwtKey, authorizedParties } = opts;
const { loadSession, loadUser, loadOrg, jwtKey, authorizedParties } = opts;

try {
const cookieToken = cookies['__session'];
Expand Down Expand Up @@ -46,6 +46,7 @@ export async function getAuthData(

const sessionId = sessionClaims.sid;
const userId = sessionClaims.sub;
const organizationId = sessionClaims.org_id;

const getToken = createGetToken({
sessionId,
Expand All @@ -54,12 +55,13 @@ export async function getAuthData(
fetcher: (...args) => sessions.getToken(...args),
});

const [user, session] = await Promise.all([
const [user, session, organization] = await Promise.all([
loadUser ? users.getUser(userId) : Promise.resolve(undefined),
loadSession ? sessions.getSession(sessionId) : Promise.resolve(undefined),
loadOrg && organizationId ? organizations.getOrganization({ organizationId }) : Promise.resolve(undefined),
]);

return { sessionId, userId, user, session, getToken, claims: sessionClaims };
return { sessionId, userId, user, session, organization, getToken, claims: sessionClaims };
} catch (err) {
return createSignedOutState();
}
Expand Down
3 changes: 1 addition & 2 deletions packages/react/src/contexts/ClerkContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ function deriveState(
// TODO: Instantiate an actual session resource
const session = initialState.session as any as ActiveSessionResource;

// TODO: Fix post-SSR decision
const organization = undefined;
const organization = initialState.organization as any as OrganizationResource;
return {
sessionId,
session,
Expand Down
37 changes: 32 additions & 5 deletions packages/react/src/hooks/useOrganization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,19 @@ type UseOrganizationReturn =
membershipList: undefined;
membership: undefined;
}
| {
isLoaded: true;
organization: OrganizationResource;
invitationList: undefined;
membershipList: undefined;
membership: undefined;
}
| {
isLoaded: boolean;
organization: OrganizationResource | null | undefined;
organization: OrganizationResource | null;
invitationList: OrganizationInvitationResource[] | null | undefined;
membershipList: OrganizationMembershipResource[] | null | undefined;
membership: OrganizationMembershipResource | undefined;
membership: OrganizationMembershipResource | null | undefined;
};

type UseOrganization = (params?: UseOrganizationParams) => UseOrganizationReturn;
Expand All @@ -44,8 +51,7 @@ export const useOrganization: UseOrganization = ({

const isomorphicClerk = useIsomorphicClerkContext();

// TODO re-iterate on SSR based on value of `organization`
if (!isomorphicClerk.loaded || !session || !organization) {
if (organization === undefined) {
return {
isLoaded: false,
organization: undefined,
Expand All @@ -55,6 +61,27 @@ export const useOrganization: UseOrganization = ({
};
}

if (organization === null) {
return {
isLoaded: true,
organization: null,
invitationList: null,
membershipList: null,
membership: null,
};
}

/** In SSR context we include only the organization object when loadOrg is set to true. */
if (!isomorphicClerk.loaded && organization) {
return {
isLoaded: true,
organization,
invitationList: undefined,
membershipList: undefined,
membership: undefined,
};
}

const clerk = isomorphicClerk as unknown as LoadedClerk;

const pendingInvitations = async () => {
Expand Down Expand Up @@ -83,7 +110,7 @@ export const useOrganization: UseOrganization = ({
isLoaded: !isMembershipsLoading && !isInvitationsLoading,
organization,
membershipList,
membership: getCurrentOrganizationMembership(session.user.organizationMemberships, organization.id), // your membership in the current org
membership: getCurrentOrganizationMembership(session!.user.organizationMemberships, organization.id), // your membership in the current org
invitationList,
};
};
Expand Down
7 changes: 5 additions & 2 deletions packages/types/src/ssr.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SessionJSON, UserJSON } from './json';
import { OrganizationJSON, SessionJSON, UserJSON } from './json';
import { ClerkJWTClaims } from './jwt';
import { SessionResource } from './session';
import { UserResource } from './user';
Expand All @@ -23,6 +23,8 @@ type SsrSessionState<SessionType> =
session: SessionType | undefined;
};

type SsrOrganizationState<OrganizationType> = { organization: null } | { organization: OrganizationType | undefined };

type SsrUserState<UserType> =
| {
userId: null;
Expand All @@ -41,5 +43,6 @@ export type InitialState =
userId: undefined;
session: undefined;
sessionId: undefined;
organization: undefined;
}
| (SsrSessionState<SessionJSON> & SsrUserState<UserJSON>);
| (SsrSessionState<SessionJSON> & SsrUserState<UserJSON> & SsrOrganizationState<OrganizationJSON>);

0 comments on commit 0889bde

Please sign in to comment.