Skip to content

Commit

Permalink
- fixes #2153, attempt to fix 401 unauthorized error when implementin…
Browse files Browse the repository at this point in the history
…g OIDC
  • Loading branch information
AmruthPillai committed Jan 15, 2025
1 parent 9a34e4a commit 63db927
Show file tree
Hide file tree
Showing 16 changed files with 223 additions and 200 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@ STORAGE_SKIP_BUCKET_CHECK=false
# GOOGLE_CALLBACK_URL=http://localhost:5173/api/auth/google/callback

# OpenID (Optional)
# VITE_OPENID_NAME=
# OPENID_AUTHORIZATION_URL=
# OPENID_CALLBACK_URL=http://localhost:5173/api/auth/openid/callback
# OPENID_CLIENT_ID=
# OPENID_CLIENT_SECRET=
# OPENID_ISSUER=
# OPENID_SCOPE=openid profile email
# OPENID_TOKEN_URL=
# OPENID_USER_INFO_URL=
2 changes: 1 addition & 1 deletion apps/client/src/pages/auth/_components/social-auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const SocialAuth = () => {
>
<a href="/api/auth/openid">
<Fingerprint className="mr-3 size-4" />
{t`OpenID`}
{import.meta.env.VITE_OPENID_NAME}
</a>
</Button>
)}
Expand Down
2 changes: 2 additions & 0 deletions apps/server/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export class AuthModule {
const clientID = configService.getOrThrow("OPENID_CLIENT_ID");
const clientSecret = configService.getOrThrow("OPENID_CLIENT_SECRET");
const issuer = configService.getOrThrow("OPENID_ISSUER");
const scope = configService.getOrThrow("OPENID_SCOPE");
const tokenURL = configService.getOrThrow("OPENID_TOKEN_URL");
const userInfoURL = configService.getOrThrow("OPENID_USER_INFO_URL");

Expand All @@ -84,6 +85,7 @@ export class AuthModule {
clientID,
clientSecret,
issuer,
scope,
tokenURL,
userInfoURL,
userService,
Expand Down
9 changes: 5 additions & 4 deletions apps/server/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,13 @@ export class AuthService {

if (
this.configService.get("OPENID_AUTHORIZATION_URL") &&
this.configService.get("OPENID_ISSUER") &&
this.configService.get("OPENID_TOKEN_URL") &&
this.configService.get("OPENID_USER_INFO_URL") &&
this.configService.get("OPENID_CALLBACK_URL") &&
this.configService.get("OPENID_CLIENT_ID") &&
this.configService.get("OPENID_CLIENT_SECRET") &&
this.configService.get("OPENID_CALLBACK_URL")
this.configService.get("OPENID_ISSUER") &&
this.configService.get("OPENID_SCOPE") &&
this.configService.get("OPENID_TOKEN_URL") &&
this.configService.get("OPENID_USER_INFO_URL")
) {
providers.push("openid");
}
Expand Down
9 changes: 6 additions & 3 deletions apps/server/src/auth/strategy/github.strategy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BadRequestException, Injectable } from "@nestjs/common";
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { createId } from "@paralleldrive/cuid2";
import { User } from "@prisma/client";
import { ErrorMessage, processUsername } from "@reactive-resume/utils";
import { Profile, Strategy, StrategyOptions } from "passport-github2";
Expand Down Expand Up @@ -46,15 +47,17 @@ export class GitHubStrategy extends PassportStrategy(Strategy, "github") {
email,
picture,
locale: "en-US",
name: displayName,
provider: "github",
name: displayName || createId(),
emailVerified: true, // auto-verify emails
username: processUsername(username ?? email.split("@")[0]),
secrets: { create: {} },
});

done(null, user);
} catch {
} catch (error) {
Logger.error(error);

throw new BadRequestException(ErrorMessage.UserAlreadyExists);
}
}
Expand Down
9 changes: 6 additions & 3 deletions apps/server/src/auth/strategy/google.strategy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BadRequestException, Injectable } from "@nestjs/common";
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { createId } from "@paralleldrive/cuid2";
import { User } from "@prisma/client";
import { ErrorMessage, processUsername } from "@reactive-resume/utils";
import { Profile, Strategy, StrategyOptions, VerifyCallback } from "passport-google-oauth20";
Expand Down Expand Up @@ -46,15 +47,17 @@ export class GoogleStrategy extends PassportStrategy(Strategy, "google") {
email,
picture,
locale: "en-US",
name: displayName,
provider: "google",
name: displayName || createId(),
emailVerified: true, // auto-verify emails
username: processUsername(username ?? email.split("@")[0]),
secrets: { create: {} },
});

done(null, user);
} catch {
} catch (error) {
Logger.error(error);

throw new BadRequestException(ErrorMessage.UserAlreadyExists);
}
}
Expand Down
18 changes: 11 additions & 7 deletions apps/server/src/auth/strategy/openid.strategy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BadRequestException, Injectable } from "@nestjs/common";
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { User } from "@prisma/client";
import { ErrorMessage, processUsername } from "@reactive-resume/utils";
import { ErrorMessage, generateRandomName, processUsername } from "@reactive-resume/utils";
import { Profile, Strategy, StrategyOptions } from "passport-openidconnect";

import { UserService } from "@/server/user/user.service";
Expand All @@ -14,6 +14,7 @@ export class OpenIDStrategy extends PassportStrategy(Strategy, "openid") {
readonly clientID: string,
readonly clientSecret: string,
readonly issuer: string,
readonly scope: string,
readonly tokenURL: string,
readonly userInfoURL: string,
private readonly userService: UserService,
Expand All @@ -24,20 +25,21 @@ export class OpenIDStrategy extends PassportStrategy(Strategy, "openid") {
clientID,
clientSecret,
issuer,
scope,
tokenURL,
userInfoURL,
scope: "openid email profile",
} as StrategyOptions);
}

async validate(
issuer: unknown,
_issuer: unknown,
profile: Profile,
done: (err?: string | Error | null, user?: Express.User, info?: unknown) => void,
) {
const { displayName, emails, photos, username } = profile;

const email = emails?.[0].value ?? `${username}@openid.com`;
const uniqueId = generateRandomName({ length: 2, style: "lowerCase", separator: "-" });
const email = emails?.[0].value ?? `${username ?? uniqueId}@openid.com`;
const picture = photos?.[0].value;

let user: User | null = null;
Expand All @@ -58,15 +60,17 @@ export class OpenIDStrategy extends PassportStrategy(Strategy, "openid") {
email,
picture,
locale: "en-US",
name: displayName,
provider: "openid",
name: displayName || uniqueId,
emailVerified: true, // auto-verify emails
username: processUsername(username ?? email.split("@")[0]),
secrets: { create: {} },
});

done(null, user);
} catch {
} catch (error) {
Logger.error(error);

throw new BadRequestException(ErrorMessage.UserAlreadyExists);
}
}
Expand Down
2 changes: 2 additions & 0 deletions apps/server/src/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,13 @@ export const configSchema = z.object({
GOOGLE_CALLBACK_URL: z.string().url().optional(),

// OpenID (Optional)
VITE_OPENID_NAME: z.string().optional(),
OPENID_AUTHORIZATION_URL: z.string().url().optional(),
OPENID_CALLBACK_URL: z.string().url().optional(),
OPENID_CLIENT_ID: z.string().optional(),
OPENID_CLIENT_SECRET: z.string().optional(),
OPENID_ISSUER: z.string().optional(),
OPENID_SCOPE: z.string().optional(),
OPENID_TOKEN_URL: z.string().url().optional(),
OPENID_USER_INFO_URL: z.string().url().optional(),
});
Expand Down
4 changes: 3 additions & 1 deletion libs/utils/src/namespaces/string.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Config as UniqueNamesConfig } from "unique-names-generator";
import { adjectives, animals, uniqueNamesGenerator } from "unique-names-generator";

import type { LayoutLocator, SortablePayload } from "./types";
Expand Down Expand Up @@ -30,12 +31,13 @@ export const extractUrl = (string: string) => {
return result ? result[0] : null;
};

export const generateRandomName = () => {
export const generateRandomName = (options?: Omit<UniqueNamesConfig, "dictionaries">) => {
return uniqueNamesGenerator({
dictionaries: [adjectives, adjectives, animals],
style: "capital",
separator: " ",
length: 3,
...options,
});
};

Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@reactive-resume/source",
"description": "A free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.",
"version": "4.3.8",
"version": "4.3.9",
"license": "MIT",
"private": true,
"author": {
Expand Down Expand Up @@ -96,7 +96,7 @@
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-lingui": "^0.9.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-prettier": "^5.2.2",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-simple-import-sort": "^12.1.1",
Expand All @@ -107,7 +107,7 @@
"jest-environment-node": "^29.7.0",
"jsdom": "^25.0.1",
"nx": "^19.8.14",
"postcss": "^8.5.0",
"postcss": "^8.5.1",
"postcss-import": "^16.1.0",
"postcss-nested": "^6.2.0",
"prettier": "^3.4.2",
Expand Down Expand Up @@ -195,7 +195,7 @@
"deepmerge": "^4.3.1",
"express-session": "^1.18.1",
"file-saver": "^2.0.5",
"framer-motion": "^11.17.1",
"framer-motion": "^11.18.0",
"fuzzy": "^0.1.3",
"helmet": "^7.2.0",
"immer": "^10.1.1",
Expand Down
Loading

0 comments on commit 63db927

Please sign in to comment.