Welcome to the Kinde community.

A
A
A
M
T
Members
saM69420
s
saM69420
Offline, last seen 3 weeks ago
Joined September 23, 2024
I'm trying to figure out the correct workflow when setting up a new application and i'm a little confused about environments.

What is the correct way of setting up environments for a new application? Currently my experience looks like this:

  • Sign in to my kinde account, or create an account
  • Add a new business for my app
  • Navigate to that business and select start project from scratch
  • Select Nextjs as the framework
  • select social providers and email
  • Select connect to get to the quick start where I can copy all my env vars and “start quickly”
This seems really easy and simple, but I’m automatically put into my production environment with no other environments available. I think I actually want a localhost environment to test things out with. So then I:

  • Add environment (local or dev or something)
  • Switch to that environment
I have a backend and a frontend application in this new environment even though I only had a next.js environment in my initially setup production environment.

  • Delete the frontend app
  • Go to settings/authentication to add social connections
  • select the backend app
  • Select Nextjs as the framework and go through the quick start
It seems easy to just use production but a bit awkward to get a dev environment the way i'm doing it
21 comments
s
O
e
Hey I was just hoping to get some advice/validation on code I've written for using Kinde with a bun and hono app. I'm using the typescript SDK.

My session manager is storing all the session items in cookies as the next.js libary does. Then I have some custom middleware for protected routes.

My backend is serving up a react app, the cookies get sent with every request, and everything is working there. I have a /api/me endpoint that checks if the user is logged in. The react app calls that endpoint when it first loads to check if the user is logged in.

Plain Text
// auth.ts
import {
  createKindeServerClient,
  GrantType,
  SessionManager,
  UserType,
} from "@kinde-oss/kinde-typescript-sdk";

import { Hono, Context, MiddlewareHandler } from "hono";
import { getCookie, setCookie, deleteCookie } from "hono/cookie";

export const kindeClient = createKindeServerClient(
  GrantType.AUTHORIZATION_CODE,
  {
    authDomain: process.env.KINDE_DOMAIN!,
    clientId: process.env.KINDE_CLIENT_ID!,
    clientSecret: process.env.KINDE_CLIENT_SECRET!,
    redirectURL: process.env.KINDE_REDIRECT_URI!,
    logoutRedirectURL: process.env.KINDE_LOGOUT_REDIRECT_URI!,
  }
);

export const sessionManager = (c: Context): SessionManager => ({
  async getSessionItem(key: string) {
    const result = getCookie(c, key);
    return result;
  },
  async setSessionItem(key: string, value: unknown) {
    if (typeof value === "string") {
      setCookie(c, key, value);
    } else {
      setCookie(c, key, JSON.stringify(value));
    }
  },
  async removeSessionItem(key: string) {
    deleteCookie(c, key);
  },
  async destroySession() {
    ["id_token", "access_token", "user", "refresh_token"].forEach((key) => {
      deleteCookie(c, key);
    });
  },
});

export const protectRoute: MiddlewareHandler = async (c, next) => {
  try {
    const manager = sessionManager(c);
    const isAuthenticated = await kindeClient.isAuthenticated(manager);
    if (!isAuthenticated) {
      return c.json({ error: "Unauthorized" }, 401);
    }
    await next();
  } catch (e) {
    console.error(e);
    return c.json({ error: "Unauthorized" }, 401);
  }
};

export const getUser: MiddlewareHandler<{
  Variables: {
    user: UserType;
  };
}> = async (c, next) => {
  try {
    const manager = sessionManager(c);
    const isAuthenticated = await kindeClient.isAuthenticated(manager);
    if (!isAuthenticated) {
      return c.json({ error: "Unauthorized" }, 401);
    }
    const profile = await kindeClient.getUserProfile(manager);
    c.set("user", profile);
    await next();
  } catch (e) {
    console.error(e);
    return c.json({ error: "Unauthorized" }, 401);
  }
};

export const authRoutes = new Hono()
  .get("/logout", async (c) => {
    const logoutUrl = await kindeClient.logout(sessionManager(c));
    return c.redirect(logoutUrl.toString());
  })
  .get("/login", async (c) => {
    const loginUrl = await kindeClient.login(sessionManager(c));
    return c.redirect(loginUrl.toString());
  })
  .get("/register", async (c) => {
    const registerUrl = await kindeClient.register(sessionManager(c));
    return c.redirect(registerUrl.toString());
  })
  .get("/callback", async (c) => {
    await kindeClient.handleRedirectToApp(
      sessionManager(c),
      new URL(c.req.url)
    );
    return c.redirect("/");
  });


Plain Text
// app.ts
import { Hono } from "hono";
import { serveStatic } from "hono/bun";

import { authRoutes, getUser } from "./auth";
import expenseRoute from "./expenses";

const app = new Hono();

const apiRoutes = app
  .basePath("/api")
  .route("/expenses", expenseRoute)
  .get("/me", getUser, async (c) => {
    const user = await c.var.user;
    return c.json({ user });
  });

app.route("/", authRoutes);

// app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))
app.get("*", serveStatic({ root: "./frontend/dist" }));
app.get("*", serveStatic({ path: "./frontend/dist/index.html" }));

export default app;
export type ApiRoutes = typeof apiRoutes;
9 comments
l
s
O
Can I customize the registration fields? I would like to remove the first name and last name, just provide your email and you're in.
5 comments
J
A
s
Plain Text
Type error: Route "src/app/api/auth/[kindeAuth]/route.ts" does not match the required types of a Next.js Route.
  Invalid configuration "GET":
    Expected "Function | undefined", got "Promise<void | Response> | ((req: NextApiRequest | Request, res: Response | NextApiResponse) => Promise<...>)".

   Linting and checking validity of types  ...error: script "build" exited with code 1 (SIGHUP)


This was already mentioned in support (1174134934265397289) but I think it deserves a bug report thread.

---

Set up Kinde Auth Route Handlers

https://kinde.com/docs/developer-tools/nextjs-sdk/#set-up-kinde-auth-route-handlers

Plain Text
import {handleAuth} from "@kinde-oss/kinde-auth-nextjs/server";

export const GET = handleAuth();


This code causes the error when you try to build a typescript next.js app.

The reason is that the default export in handlers/auth.js can return a promise for backwards compatibility, but won't ever return a promise when called with no params like we are here.

https://github.com/kinde-oss/kinde-auth-nextjs/blob/main/src/handlers/auth.js

---

Temporary Solution:

Plain Text
export const GET = handleAuth() as any


or

Plain Text
export const GET = handleAuth() as (req: Request, res: Response) => Promise<void>



Not sure about long term solutions. Does JSDoc work with overloading functions and typescript?
7 comments
A
O
s
On the Kinde dashboard, when I go to enable email authentication, that error appears in the console and I can't select or deselect Passwordless or Password. I'm stuck with nothing.

I get the same issue when I try to delete an app.

Plain Text
toggleDisabled.js:6 Uncaught DOMException: Failed to execute 'querySelectorAll' on 'Document': '"[name='p_email_auth_type']"' is not a valid selector.


The options remain disabled and I have to delete that manually from the html to submit the form.

Is this the right place to post things like this?
4 comments
O
A
s