Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""
GITHUB_ID=""
GITHUB_SECRET=""
KEYCLOAK_ID="" # Keycloak ClientID
KEYCLOAK_SECRET="" # Keycloak ClientSecret(require client authentication)
KEYCLOAK_ISSUER="" # Keycloak realms url(https://example.com/realms/master)


# AWS S3
AWS_ENDPOINT=""
AWS_REGION=""
AWS_KEY_ID=""
AWS_SECRET_ACCESS_KEY=""
AWS_BUCKET_NAME=""
AWS_FORCE_PATH_STYLE="false" # Change to true when using Minio

# QStash
QSTASH_CURRENT_SIGNING_KEY=""
Expand All @@ -38,4 +43,4 @@ POSTHOG_PROXY_PATH="ioafe"

# redis for ratelimiting
UPSTASH_REDIS_REST_URL=""
UPSTASH_REDIS_REST_TOKEN=""
UPSTASH_REDIS_REST_TOKEN=""
8 changes: 8 additions & 0 deletions src/env.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ const server = z.object({
GOOGLE_CLIENT_SECRET: z.string().nullish(),
GITHUB_ID: z.string(),
GITHUB_SECRET: z.string(),
KEYCLOAK_ID: z.string().nullish(),
KEYCLOAK_SECRET: z.string().nullish(),
KEYCLOAK_ISSUER: z.string().nullish(),
AWS_ENDPOINT: z.string(),
AWS_REGION: z.string(),
AWS_KEY_ID: z.string(),
AWS_SECRET_ACCESS_KEY: z.string(),
AWS_BUCKET_NAME: z.string(),
AWS_FORCE_PATH_STYLE: z.string().nullish(),
STRIPE_SECRET_KEY: z.string().nullish(),
STRIPE_WEBHOOK_SECRET: z.string().nullish(),
STRIPE_MONTHLY_PRICE_ID: z.string().nullish(),
Expand Down Expand Up @@ -66,11 +70,15 @@ const processEnv = {
GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
GITHUB_ID: process.env.GITHUB_ID,
GITHUB_SECRET: process.env.GITHUB_SECRET,
KEYCLOAK_ID: process.env.KEYCLOAK_ID,
KEYCLOAK_SECRET: process.env.KEYCLOAK_SECRET,
KEYCLOAK_ISSUER: process.env.KEYCLOAK_ISSUER,
AWS_ENDPOINT: process.env.AWS_ENDPOINT,
AWS_REGION: process.env.AWS_REGION,
AWS_KEY_ID: process.env.AWS_KEY_ID,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
AWS_BUCKET_NAME: process.env.AWS_BUCKET_NAME,
AWS_FORCE_PATH_STYLE: process.env.AWS_FORCE_PATH_STYLE,
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY:
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,
STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
Expand Down
36 changes: 31 additions & 5 deletions src/server/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import GitHubProvider from "next-auth/providers/github";
import KeycloakProvider from "next-auth/providers/keycloak";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { env } from "~/env.mjs";
import { prisma } from "~/server/db";
Expand All @@ -32,6 +33,18 @@ declare module "next-auth" {
}
}

const adapter = PrismaAdapter(prisma);

const _linkAccount = adapter.linkAccount;

// Required when using keycloak.
// keycloak always sends the refresh_expires_in attribute.
// prisma is extended to handle refresh_expires_in.
adapter.linkAccount = (account) => {
const { 'not-before-policy': _, refresh_expires_in, ...data } = account;
return _linkAccount(data);
};

/**
* Options for NextAuth.js used to configure adapters, providers, callbacks, etc.
*
Expand All @@ -48,7 +61,7 @@ export const authOptions: NextAuthOptions = {
},
}),
},
adapter: PrismaAdapter(prisma),
adapter: adapter,
providers: [
...(!!env.GOOGLE_CLIENT_ID && !!env.GOOGLE_CLIENT_SECRET
? [
Expand All @@ -58,10 +71,23 @@ export const authOptions: NextAuthOptions = {
}),
]
: []),
GitHubProvider({
clientId: env.GITHUB_ID,
clientSecret: env.GITHUB_SECRET,
}),
...(!!env.GITHUB_ID && !!env.GITHUB_SECRET
? [
GitHubProvider({
clientId: env.GITHUB_ID,
clientSecret: env.GITHUB_SECRET,
}),
]
: []),
...(!!env.KEYCLOAK_ID && !!env.KEYCLOAK_SECRET && !!env.KEYCLOAK_ISSUER
? [
KeycloakProvider({
clientId: env.KEYCLOAK_ID,
clientSecret: env.KEYCLOAK_SECRET,
issuer: env.KEYCLOAK_ISSUER,
}),
]
: []),
/**
* ...add more providers here.
*
Expand Down
9 changes: 9 additions & 0 deletions src/server/aws/s3.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { S3 } from "@aws-sdk/client-s3";
import { env } from "~/env.mjs";

// Isn't it better code? where is the right place to write?
function toBoolean(booleanStr: string): boolean {
return booleanStr.toLowerCase() === "true";
}

export const s3 = new S3({
endpoint: env.AWS_ENDPOINT,
region: env.AWS_REGION,
credentials: {
accessKeyId: env.AWS_KEY_ID,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
},
// A necessary option when using Minio. false is the default behavior.
// If false, the domain will be changed to [bucket name].example.com.
// If true, appends the bucket to the path, like example.com/[bucket name].
"forcePathStyle": toBoolean(env.AWS_FORCE_PATH_STYLE),
});