Skip to content

Commit

Permalink
fix: oauth state is encrypted
Browse files Browse the repository at this point in the history
  • Loading branch information
diced committed Nov 26, 2024
1 parent 5232192 commit da875e4
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 18 deletions.
8 changes: 4 additions & 4 deletions src/lib/oauth/providerUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function findProvider(
export const githubAuth = {
url: (clientId: string, state?: string, redirectUri?: string) =>
`https://github.com/login/oauth/authorize?client_id=${clientId}&scope=read:user${
state ? `&state=${state}` : ''
state ? `&state=${encodeURIComponent(state)}` : ''
}${redirectUri ? `&redirect_uri=${encodeURIComponent(redirectUri)}` : ''}`,
user: async (accessToken: string) => {
const res = await fetch('https://api.github.com/user', {
Expand All @@ -29,7 +29,7 @@ export const discordAuth = {
url: (clientId: string, origin: string, state?: string, redirectUri?: string) =>
`https://discord.com/api/oauth2/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(
redirectUri ?? `${origin}/api/auth/oauth/discord`,
)}&response_type=code&scope=identify${state ? `&state=${state}` : ''}`,
)}&response_type=code&scope=identify${state ? `&state=${encodeURIComponent(state)}` : ''}`,
user: async (accessToken: string) => {
const res = await fetch('https://discord.com/api/users/@me', {
headers: {
Expand All @@ -47,7 +47,7 @@ export const googleAuth = {
`https://accounts.google.com/o/oauth2/auth?client_id=${clientId}&redirect_uri=${encodeURIComponent(
redirectUri ?? `${origin}/api/auth/oauth/google`,
)}&response_type=code&access_type=offline&scope=https://www.googleapis.com/auth/userinfo.profile${
state ? `&state=${state}` : ''
state ? `&state=${encodeURIComponent(state)}` : ''
}`,
user: async (accessToken: string) => {
const res = await fetch('https://www.googleapis.com/oauth2/v1/userinfo?alt=json', {
Expand All @@ -65,7 +65,7 @@ export const oidcAuth = {
url: (clientId: string, origin: string, authorizeUrl: string, state?: string, redirectUri?: string) =>
`${authorizeUrl}?client_id=${clientId}&redirect_uri=${encodeURIComponent(
redirectUri ?? `${origin}/api/auth/oauth/oidc`,
)}&response_type=code&scope=openid+email+profile+offline_access${state ? `&state=${state}` : ''}`,
)}&response_type=code&scope=openid+email+profile+offline_access${state ? `&state=${encodeURIComponent(state)}` : ''}`,
user: async (accessToken: string, userInfoUrl: string) => {
const res = await fetch(userInfoUrl, {
headers: {
Expand Down
11 changes: 9 additions & 2 deletions src/lib/oauth/withOAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { NextApiReq, NextApiRes } from '@/lib/response';
import { OAuthProviderType } from '@prisma/client';
import { prisma } from '../db';
import { findProvider } from './providerUtil';
import { createToken } from '../crypto';
import { createToken, decrypt } from '../crypto';
import { config } from '../config';
import { User } from '../db/models/user';
import Logger, { log } from '../logger';
Expand Down Expand Up @@ -88,7 +88,14 @@ export const withOAuth =

const userOauth = findProvider(provider, user?.oauthProviders ?? []);

if (state === 'link') {
let urlState;
try {
urlState = decrypt(decodeURIComponent(state ?? ''), config.core.secret);
} catch {
urlState = null;
}

if (urlState === 'link') {
if (!user) return res.unauthorized('invalid session');

if (findProvider(provider, user.oauthProviders))
Expand Down
10 changes: 7 additions & 3 deletions src/pages/api/auth/oauth/discord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import enabled from '@/lib/oauth/enabled';
import { discordAuth } from '@/lib/oauth/providerUtil';
import { fetchToDataURL } from '@/lib/base64';
import Logger from '@/lib/logger';
import { encrypt } from '@/lib/crypto';

async function handler({ code, state, host }: OAuthQuery, logger: Logger): Promise<OAuthResponse> {
async function handler({ code, host }: OAuthQuery, logger: Logger): Promise<OAuthResponse> {
if (!config.features.oauthRegistration)
return {
error: 'OAuth registration is disabled.',
Expand All @@ -22,15 +23,18 @@ async function handler({ code, state, host }: OAuthQuery, logger: Logger): Promi
error_code: 401,
};

if (!code)
if (!code) {
const linkState = encrypt('link', config.core.secret);

return {
redirect: discordAuth.url(
config.oauth.discord.clientId!,
`${config.core.returnHttpsUrls ? 'https' : 'http'}://${host}`,
state,
linkState,
config.oauth.discord.redirectUri ?? undefined,
),
};
}

const body = new URLSearchParams({
client_id: config.oauth.discord.clientId!,
Expand Down
10 changes: 7 additions & 3 deletions src/pages/api/auth/oauth/github.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { fetchToDataURL } from '@/lib/base64';
import { config } from '@/lib/config';
import { encrypt } from '@/lib/crypto';
import Logger from '@/lib/logger';
import { combine } from '@/lib/middleware/combine';
import { method } from '@/lib/middleware/method';
import enabled from '@/lib/oauth/enabled';
import { githubAuth } from '@/lib/oauth/providerUtil';
import { OAuthQuery, OAuthResponse, withOAuth } from '@/lib/oauth/withOAuth';

async function handler({ code, state }: OAuthQuery, logger: Logger): Promise<OAuthResponse> {
async function handler({ code }: OAuthQuery, logger: Logger): Promise<OAuthResponse> {
if (!config.features.oauthRegistration)
return {
error: 'OAuth registration is disabled.',
Expand All @@ -22,14 +23,17 @@ async function handler({ code, state }: OAuthQuery, logger: Logger): Promise<OAu
error_code: 401,
};

if (!code)
if (!code) {
const linkState = encrypt('link', config.core.secret);

return {
redirect: githubAuth.url(
config.oauth.github.clientId!,
state,
linkState,
config.oauth.github.redirectUri ?? undefined,
),
};
}

const body = JSON.stringify({
client_id: config.oauth.github.clientId!,
Expand Down
10 changes: 7 additions & 3 deletions src/pages/api/auth/oauth/google.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { fetchToDataURL } from '@/lib/base64';
import { config } from '@/lib/config';
import { encrypt } from '@/lib/crypto';
import Logger from '@/lib/logger';
import { combine } from '@/lib/middleware/combine';
import { method } from '@/lib/middleware/method';
import enabled from '@/lib/oauth/enabled';
import { googleAuth } from '@/lib/oauth/providerUtil';
import { OAuthQuery, OAuthResponse, withOAuth } from '@/lib/oauth/withOAuth';

async function handler({ code, state, host }: OAuthQuery, _logger: Logger): Promise<OAuthResponse> {
async function handler({ code, host }: OAuthQuery, _logger: Logger): Promise<OAuthResponse> {
if (!config.features.oauthRegistration)
return {
error: 'OAuth registration is disabled.',
Expand All @@ -22,15 +23,18 @@ async function handler({ code, state, host }: OAuthQuery, _logger: Logger): Prom
error_code: 401,
};

if (!code)
if (!code) {
const linkState = encrypt('link', config.core.secret);

return {
redirect: googleAuth.url(
config.oauth.google.clientId!,
`${config.core.returnHttpsUrls ? 'https' : 'http'}://${host}`,
state,
linkState,
config.oauth.google.redirectUri ?? undefined,
),
};
}

const body = new URLSearchParams({
client_id: config.oauth.google.clientId!,
Expand Down
10 changes: 7 additions & 3 deletions src/pages/api/auth/oauth/oidc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { config } from '@/lib/config';
import { encrypt } from '@/lib/crypto';
import Logger from '@/lib/logger';
import { combine } from '@/lib/middleware/combine';
import { method } from '@/lib/middleware/method';
Expand All @@ -7,7 +8,7 @@ import { oidcAuth } from '@/lib/oauth/providerUtil';
import { OAuthQuery, OAuthResponse, withOAuth } from '@/lib/oauth/withOAuth';

// thanks to @danejur for this https://github.com/diced/zipline/pull/372
async function handler({ code, state, host }: OAuthQuery, _logger: Logger): Promise<OAuthResponse> {
async function handler({ code, host }: OAuthQuery, _logger: Logger): Promise<OAuthResponse> {
if (!config.features.oauthRegistration)
return {
error: 'OAuth registration is disabled.',
Expand All @@ -22,16 +23,19 @@ async function handler({ code, state, host }: OAuthQuery, _logger: Logger): Prom
error_code: 401,
};

if (!code)
if (!code) {
const linkState = encrypt('link', config.core.secret);

return {
redirect: oidcAuth.url(
config.oauth.oidc.clientId!,
`${config.core.returnHttpsUrls ? 'https' : 'http'}://${host}`,
config.oauth.oidc.authorizeUrl!,
state,
linkState,
config.oauth.oidc.redirectUri ?? undefined,
),
};
}

const body = new URLSearchParams({
client_id: config.oauth.oidc.clientId!,
Expand Down

0 comments on commit da875e4

Please sign in to comment.