Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tried all the things but it always shows the null in the terminal after the post signUp is completed. #77

Open
pantboi2703 opened this issue Nov 7, 2024 · 8 comments

Comments

@pantboi2703
Copy link

GET /sign-up 200 in 164ms
Error: No session
at createSessionClient (webpack-internal:///(rsc)/./lib/appwrite.ts:21:15)
at getLoggedInUser (webpack-internal:///(rsc)/./lib/actions/user.actions.ts:58:97)
at SignUp (webpack-internal:///(rsc)/./app/(auth)/sign-up/page.tsx:16:106)
at e_ (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:263963)
at e (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:268095)
at eF (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:268583)
at eq (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:274547)
at ej (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:264791)
at e_ (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:263833)
at e (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:268095)
at eF (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:268583)
at /home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:265814
at Array.toJSON (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:266278)
at stringify ()
at eq (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:274646)
at eJ (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:275164)
at AsyncLocalStorage.run (node:internal/async_local_storage/async_hooks:91:14)
at Timeout._onTimeout (/home/mayank/banking/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:283159)
at listOnTimeout (node:internal/timers:594:17)
at process.processTimers (node:internal/timers:529:7)
null
POST /sign-up 200 in 1468ms

@mr-andrej
Copy link

Hey @pantboi2703! The error No session at createSessionClient usually means that the session isn't properly created or maintained after user registration. This typically happens when there's a mismatch in the authentication flow.

What we can try is debug it, could you share:

  1. Your "appwrite.ts" file
  2. Anything else you're worried about/could be relevant

I'm no expert myself but maybe we can figure this out. If by any chance you already found the source of your issue, it would be useful to share it here for anyone else that might have the same issue. Regardless of whether you want to share the solution. if you don't have the issue anymore feel free to close this issue as resolved!

@pantboi2703
Copy link
Author

This is my appwrite.ts file code:-

'use server';

import { ID } from "node-appwrite";
import { createAdminClient, createSessionClient } from "../appwrite";
import { cookies } from "next/headers";
import { parseStringify } from "../utils";

export const signIn = async ({ email, password}:
signInProps) => {
try {
// Mutation / Database / Make fetch
const { account } = await createAdminClient();

  const response = await account.createEmailPasswordSession(email, password);

  if (response) { 
    cookies().set("appwrite-session", response.secret, {
      path: "/",
      httpOnly: true, 
      sameSite: "strict",
      secure: true, 
      });     
  }
  
  
  return parseStringify(response);
} catch(error) {
    console.error('Error',error);
}

}

export const signUp = async (userData: SignUpParams) => {
const { email, password, firstName, lastName} = userData
try {
// Mutation / Database / Make fetch
const { account } = await createAdminClient();

    const newUserAccount = await account.create(
        ID.unique(),
        userData.email,
        userData.password,
        `${firstName} ${lastName}`
    );
    const session = await account.createEmailPasswordSession(email, password);

    cookies().set("appwrite-session", session.secret, {
        path: "/",
        httpOnly: true,
        sameSite: "strict",
        secure: true,
    });

    return parseStringify(newUserAccount);
} catch(error) {
    console.error('Error',error);
}

}

// ... your initilization functions

export async function getLoggedInUser() {
try {
const { account } = await createSessionClient();

  const user = await account.get();

  return parseStringify(user);
} catch (error) {
  console.log(error);
  return null;
}

}

export const logoutAccount = async () => {
try {
const { account } = await createSessionClient();

  cookies().delete('appwrite-session');

  await account.deleteSession('current');
} catch (error) {
  return null;
}

}

@mr-andrej
Copy link

This seems more like the user.actions.ts file. I'll post my appwrite.ts, perhaps you could get lucky with a copy and paste if the issue lies within the appwrite.ts

"use server";

import {Account, Client, Databases, Users} from "node-appwrite";
import {cookies} from "next/headers";

export async function createSessionClient() {
    const client = new Client()
        .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT)
        .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT);

    const sessionName = "appwrite-session";
    const session = cookies().get(sessionName);

    if (!session) {
        throw new Error("No session");
    }

    client.setSession(session.value);

    return {
        get account() {
            return new Account(client);
        },
    };
}

export async function createAdminClient() {
    const client = new Client()
        .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!)
        .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT!)
        .setKey(process.env.NEXT_APPWRITE_KEY!);

    return {
        get account() {
            return new Account(client);
        },
        get database() {
            return new Databases(client);
        },
        get user() {
            return new Users(client);
        },
    };
}

@pantboi2703
Copy link
Author

Hey @mr-andrej can you please show me your user.actions.ts file

@tskxz
Copy link

tskxz commented Nov 13, 2024

Same thing happening to me

@tskxz
Copy link

tskxz commented Nov 13, 2024

This seems more like the user.actions.ts file. I'll post my appwrite.ts, perhaps you could get lucky with a copy and paste if the issue lies within the appwrite.ts

"use server";

import {Account, Client, Databases, Users} from "node-appwrite";
import {cookies} from "next/headers";

export async function createSessionClient() {
    const client = new Client()
        .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT)
        .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT);

    const sessionName = "appwrite-session";
    const session = cookies().get(sessionName);

    if (!session) {
        throw new Error("No session");
    }

    client.setSession(session.value);

    return {
        get account() {
            return new Account(client);
        },
    };
}

export async function createAdminClient() {
    const client = new Client()
        .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!)
        .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT!)
        .setKey(process.env.NEXT_APPWRITE_KEY!);

    return {
        get account() {
            return new Account(client);
        },
        get database() {
            return new Databases(client);
        },
        get user() {
            return new Users(client);
        },
    };
}

now I got Server Error: User (role: guests) missing scope (account)

@mr-andrej
Copy link

@pantboi2703 My user.actions.ts (you can find all my files on my GitHub, though some of the code will differ from what Adrian showed):

"use server";

import {createAdminClient, createSessionClient} from "../appwrite";
import {ID, Query} from "node-appwrite";
import {encryptId, extractCustomerIdFromUrl, parseStringify} from "@/lib/utils";
import {cookies} from "next/headers";
import {CountryCode, ProcessorTokenCreateRequest, ProcessorTokenCreateRequestProcessorEnum, Products} from "plaid";
import {plaidClient} from "@/lib/plaid";
import {revalidatePath} from "next/cache";
import {addFundingSource, createDwollaCustomer} from "@/lib/actions/dwolla.actions";
import {
    createBankAccountProps,
    exchangePublicTokenProps,
    getBankByAccountIdProps,
    getBankProps,
    getBanksProps,
    getUserInfoProps,
    NewDwollaCustomerParams,
    signInProps,
    SignUpParams,
    User,
} from "@/types";

const {
    APPWRITE_DATABASE_ID: DATABASE_ID,
    APPWRITE_USER_COLLECTION_ID: USER_COLLECTION_ID,
    APPWRITE_BANK_COLLECTION_ID: BANK_COLLECTION_ID,
} = process.env;

export const getUserInfo = async ({userId}: getUserInfoProps) => {
    try {
        const {database} = await createAdminClient();

        const user = await database.listDocuments(
            DATABASE_ID!,
            USER_COLLECTION_ID!,
            [Query.equal("userId", [userId])],
        );

        return parseStringify(user.documents[0]);
    } catch (error) {
        console.log(error);
    }
};

export const signIn = async ({email, password}: signInProps) => {
    try {
        const {account} = await createAdminClient();
        const session = await account.createEmailPasswordSession(email, password);

        const cookiesStore = cookies();
        (cookiesStore as any).set("appwrite-session", session.secret, {
            path: "/",
            httpOnly: true,
            sameSite: "strict",
            secure: true,
        });

        const user = await getUserInfo({userId: session.userId});

        return parseStringify(user);
    } catch (error) {
        console.error("Error", error);
    }
};

export const signUp = async ({password, ...userData}: SignUpParams) => {
    const {email, firstName, lastName} = userData;

    let newUserAccount;

    try {
        const {account, database} = await createAdminClient();

        newUserAccount = await account.create(
            ID.unique(),
            email,
            password,
            `${firstName} ${lastName}`,
        );

        if (!newUserAccount) {
            throw new Error("Error creating a user");
        }

        const dwollaCustomerUrl = await createDwollaCustomer({
            ...userData,
            type: "personal",
        } as NewDwollaCustomerParams);

        if (!dwollaCustomerUrl) {
            throw new Error("Error creating a Dwolla customer");
        }

        const dwollaCustomerId = extractCustomerIdFromUrl(dwollaCustomerUrl);

        const newUser = await database.createDocument(
            DATABASE_ID!,
            USER_COLLECTION_ID!,
            ID.unique(),
            {
                ...userData,
                userId: newUserAccount.$id,
                dwollaCustomerId,
                dwollaCustomerUrl,
            },
        );

        const session = await account.createEmailPasswordSession(email, password);

        const cookiesStore = cookies();
        (cookiesStore as any).set("appwrite-session", session.secret, {
            path: "/",
            httpOnly: true,
            sameSite: "strict",
            secure: true,
        });

        return parseStringify(newUser);
    } catch (error) {
        console.error("Error", error);
    }
};

export async function getLoggedInUser() {
    try {
        const {account} = await createSessionClient();
        const result = await account.get();

        const user = await getUserInfo({userId: result.$id});

        return parseStringify(user);
    } catch (error) {
        return null;
    }
}

export const logoutAccount = async () => {
    try {
        const {account} = await createSessionClient();

        cookies().delete("appwrite-session" as any); // Because nothing but as any worked here, obscure type issue

        await account.deleteSession("current");
    } catch (error) {
        return null;
    }
};

export const createLinkToken = async (user: User) => {
    try {
        const tokenParams = {
            user: {
                client_user_id: user.$id,
            },
            client_name: `${user.firstName} ${user.lastName}`,
            products: ["auth", "transactions"] as Products[],
            language: "en",
            country_codes: ["US", "FR"] as CountryCode[],
        };

        const response = await plaidClient.linkTokenCreate(tokenParams);

        return parseStringify({linkToken: response.data.link_token});
    } catch (error) {
        console.log(error);
    }
};

export const createBankAccount = async (
    {
        userId,
        bankId,
        accountId,
        accessToken,
        fundingSourceUrl,
        shareableId,
    }: createBankAccountProps) => {
    try {
        const {database} = await createAdminClient();

        const bankAccount = await database.createDocument(
            DATABASE_ID!,
            BANK_COLLECTION_ID!,
            ID.unique(),
            {
                userId,
                bankId,
                accountId,
                accessToken,
                fundingSourceUrl,
                shareableId,
            },
        );

        return parseStringify(bankAccount);
    } catch (Error) {

    }
};

export const exchangePublicToken = async ({publicToken, user}: exchangePublicTokenProps) => {
    try {
        // Exchange public token for access token and item ID
        const response = await plaidClient.itemPublicTokenExchange({
            public_token: publicToken,
        });

        const accessToken = response.data.access_token;
        const itemId = response.data.item_id;

        // Get account information from Plaid using the access token
        const accountsResponse = await plaidClient.accountsGet({
            access_token: accessToken,
        });

        const accountData = accountsResponse.data.accounts[0];

        // Create a processor token for Dwolla using the access token and account ID
        const request: ProcessorTokenCreateRequest = {
            access_token: accessToken,
            account_id: accountData.account_id,
            processor: "dwolla" as ProcessorTokenCreateRequestProcessorEnum,
        };

        const processorTokenResponse = await plaidClient.processorTokenCreate(request);
        const processorToken = processorTokenResponse.data.processor_token;

        // Create a funding source URL for the account using the Dwolla customer ID, processor token, and bank name
        const fundingSourceUrl = await addFundingSource({
            dwollaCustomerId: user.dwollaCustomerId,
            processorToken,
            bankName: accountData.name,
        });

        // If the funding source URL is not created, throw an error
        if (!fundingSourceUrl) {
            throw Error;
        }

        // Create a bank account using the user ID, item ID, account ID, access token, funding source URL, and sharable ID
        await createBankAccount({
            userId: user.$id,
            bankId: itemId,
            accountId: accountData.account_id,
            accessToken,
            fundingSourceUrl,
            shareableId: encryptId(accountData.account_id),
        });

        // Revalidate the path to reflect the changes
        revalidatePath("/");

        // Return a success message
        return parseStringify({publicTokenExchange: "complete"});
    } catch (error) {
        console.log(error);
    }
};


export const getBanks = async ({userId}: getBanksProps) => {
    try {
        const {database} = await createAdminClient();
        const banks = await database.listDocuments(
            DATABASE_ID!,
            BANK_COLLECTION_ID!,
            [Query.equal("userId", [userId])],
        );

        return parseStringify(banks.documents);
    } catch (error) {
        console.log(error);
    }
};

export const getBank = async ({documentId}: getBankProps) => {
    try {
        const {database} = await createAdminClient();

        const bank = await database.listDocuments(
            DATABASE_ID!,
            BANK_COLLECTION_ID!,
            [Query.equal("$id", [documentId])],
        );

        return parseStringify(bank.documents[0]);
    } catch (error) {
        console.log(error);
    }
};

export const getBankByAccountId = async ({accountId}: getBankByAccountIdProps) => {
    try {
        const {database} = await createAdminClient();

        const bank = await database.listDocuments(
            DATABASE_ID!,
            BANK_COLLECTION_ID!,
            [Query.equal("accountId", [accountId])],
        );

        if (bank.total !== 1) return null;

        return parseStringify(bank.documents[0]);
    } catch (error) {
        console.log(error);
    }
};

@mr-andrej
Copy link

@tskxz Off the top of my head I could think of a few fixes for that error:

  1. Ensure NEXT_PUBLIC_APPWRITE_ENDPOINT, NEXT_PUBLIC_APPWRITE_PROJECT, and NEXT_APPWRITE_KEY are properly set. (Since it seems like an authentication issue)
  2. If the user is not authenticated, they cannot access account-related information. You should confirm that the session token exists and is valid. Check if session.value from cookies().get(sessionName) is being properly set upon authentication. If session is undefined or invalid, users will be treated as guests, resulting in the error. (From my understanding)

Make sure to review the video tutorial around the moment when things stopped working, trying to get a sense of what could have gone wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants