MCPcopy Index your code
hub / github.com/benawad/how-to-roll-your-own-auth

github.com/benawad/how-to-roll-your-own-auth @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
16 symbols 50 edges 20 files 0 documented · 0%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

How to roll your own auth

This repo is a companion to this YouTube video: https://youtu.be/CcrgG5MjGOk

  1. Discord OAUTH with passport.js
passport.use(
    new Strategy(
      {
        clientId: process.env.DISCORD_CLIENT_ID!,
        clientSecret: process.env.DISCORD_SECRET_ID!,
        callbackUrl: `${process.env.API_URL}/auth/discord/callback`,
        scope: ["identify"],
      },

      async (_accessToken, _refreshToken, profile, done) => {
        // 1. grab id
        const discordId = profile._json.id as string;

        // 2. db lookup
        let user = await db.query.users.findFirst({
          where: eq(usersTable.discordId, discordId),
        });

        // 3. create user if not exists
        if (!user) {
          [user] = await db
            .insert(usersTable)
            .values({
              discordId,
            })
            .returning();
        }

        // 4. return user
        done(null, user);
      }
    ) as any
  );
  1. JWTs
const createAuthTokens = (
  user: DbUser
): { refreshToken: string; accessToken: string } => {
  const refreshToken = jwt.sign(
    { userId: user.id, refreshTokenVersion: user.refreshTokenVersion },
    process.env.REFRESH_TOKEN_SECRET!,
    {
      expiresIn: "30d",
    }
  );

  const accessToken = jwt.sign(
    { userId: user.id },
    process.env.ACCESS_TOKEN_SECRET!,
    {
      expiresIn: "15min",
    }
  );

  return { refreshToken, accessToken };
};
  1. Cookies
// __prod__ is a boolean that is true when the NODE_ENV is "production"
const cookieOpts = {
  httpOnly: true,
  secure: __prod__,
  sameSite: "lax",
  path: "/",
  domain: __prod__ ? `.${process.env.DOMAIN}` : "",
  maxAge: 1000 * 60 * 60 * 24 * 365 * 10, // 10 year
} as const;

export const sendAuthCookies = (res: Response, user: DbUser) => {
  const { accessToken, refreshToken } = createAuthTokens(user);
  res.cookie("id", accessToken, cookieOpts);
  res.cookie("rid", refreshToken, cookieOpts);
};

How to deploy server to VPS

Get a VPS like Hostinger if you don't already have one. Use code BENAWAD at checkout for additional savings (SPONSORED)

  1. Save yourself some hassle and setup passwordless ssh into your VPS: https://www.hostinger.com/tutorials/how-to-setup-passwordless-ssh/
  2. Install Dokku on your VPS https://dokku.com/docs/getting-started/installation/ (I like to use this for zero-downtime deployments)
  3. The latest version of Ubuntu that Dokku works with is 22.04 (you can change versions in Hostinger's dashboard)
  4. Create an app dokku apps:create api
  5. Create database https://dokku.com/docs/deployment/application-deployment/?h=postgresql#create-the-backing-services
  6. Link database dokku postgres:link pg api
  7. Create Docker image on your computer docker build -t example/auth:1 . --platform=linux
  8. Send Docker image to VPS docker image save example/auth:1 | ssh root@123.23.21.31 docker load
  9. Tag image in your VPS docker tag example/auth:1 dokku/api:latest
  10. Deploy dokku deploy api latest
  11. This will fail
  12. Set environment variables bash dokku config:set api FRONTEND_URL=https://example.com ACCESS_TOKEN_SECRET=hj890duj01jd9012j0dj9021390132 REFRESH_TOKEN_SECRET=q90wej9201je091212903291308 DISCORD_SECRET_ID=asdj902j1d0921 DISCORD_CLIENT_ID=129032180312 DOMAIN=example.com
  13. This should redeploy the app and it should work

Custom domain

  1. Setup DNS so your domain points to the VPS
  2. Setup https on your VPS using letsencrypt dokku plugin: https://github.com/dokku/dokku-letsencrypt
  3. You will need to set your domain first: dokku domains:set api api.example.com

VPS Security

https://www.hostinger.com/tutorials/vps-security

Frontend deployment

I like to use Cloudflare pages

Debugging cookies

https://github.com/benawad/how-to-debug-cookies

Extension points exported contracts — how you extend this code

ProcessEnv (Interface)
(no doc)
api/src/types/env.d.ts
LoginButtonProps (Interface)
(no doc)
web/src/app/LoginButton.tsx
DoStuffProps (Interface)
(no doc)
web/src/app/DoStuff.tsx

Core symbols most depended-on inside this repo

sendAuthCookies
called by 2
api/src/createAuthTokens.ts
checkTokens
called by 2
api/src/createAuthTokens.ts
main
called by 1
api/src/index.ts
createAuthTokens
called by 1
api/src/createAuthTokens.ts
addTrpc
called by 1
api/src/appRouter.ts
createContext
called by 0
api/src/trpc.ts
clearAuthCookies
called by 0
api/src/createAuthTokens.ts
LoginButton
called by 0
web/src/app/LoginButton.tsx

Shape

Function 13
Interface 3

Languages

TypeScript100%

Modules by API surface

api/src/createAuthTokens.ts4 symbols
web/src/app/utils/trpc.ts2 symbols
web/src/app/LoginButton.tsx2 symbols
web/src/app/DoStuff.tsx2 symbols
web/src/app/page.tsx1 symbols
web/src/app/layout.tsx1 symbols
api/src/types/env.d.ts1 symbols
api/src/trpc.ts1 symbols
api/src/index.ts1 symbols
api/src/appRouter.ts1 symbols

Datastores touched

auth-exampleDatabase · 1 repos

For agents

$ claude mcp add how-to-roll-your-own-auth \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page