mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +10:00
87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
import { CodeChallengeMethod, OAuth2Client, generateCodeVerifier, generateState } from 'arctic';
|
|
import type { Context } from 'hono';
|
|
import { setCookie } from 'hono/cookie';
|
|
|
|
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
|
|
|
import type { OAuthClientOptions } from '../../config';
|
|
import { sessionCookieOptions } from '../session/session-cookies';
|
|
import { getOpenIdConfiguration } from './open-id';
|
|
|
|
type HandleOAuthAuthorizeUrlOptions = {
|
|
/**
|
|
* Hono context.
|
|
*/
|
|
c: Context;
|
|
|
|
/**
|
|
* OAuth client options.
|
|
*/
|
|
clientOptions: OAuthClientOptions;
|
|
|
|
/**
|
|
* Optional redirect path to redirect the user somewhere on the app after authorization.
|
|
*/
|
|
redirectPath?: string;
|
|
};
|
|
|
|
const oauthCookieMaxAge = 60 * 10; // 10 minutes.
|
|
|
|
export const handleOAuthAuthorizeUrl = async (options: HandleOAuthAuthorizeUrlOptions) => {
|
|
const { c, clientOptions, redirectPath } = options;
|
|
|
|
if (!clientOptions.clientId || !clientOptions.clientSecret) {
|
|
throw new AppError(AppErrorCode.NOT_SETUP);
|
|
}
|
|
|
|
const { authorization_endpoint } = await getOpenIdConfiguration(clientOptions.wellKnownUrl, {
|
|
requiredScopes: clientOptions.scope,
|
|
});
|
|
|
|
const oAuthClient = new OAuth2Client(
|
|
clientOptions.clientId,
|
|
clientOptions.clientSecret,
|
|
clientOptions.redirectUrl,
|
|
);
|
|
|
|
const scopes = clientOptions.scope;
|
|
const state = generateState();
|
|
|
|
const codeVerifier = generateCodeVerifier();
|
|
|
|
const url = oAuthClient.createAuthorizationURLWithPKCE(
|
|
authorization_endpoint,
|
|
state,
|
|
CodeChallengeMethod.S256,
|
|
codeVerifier,
|
|
scopes,
|
|
);
|
|
|
|
// Allow user to select account during login.
|
|
url.searchParams.append('prompt', 'login');
|
|
|
|
setCookie(c, `${clientOptions.id}_oauth_state`, state, {
|
|
...sessionCookieOptions,
|
|
sameSite: 'lax',
|
|
maxAge: oauthCookieMaxAge,
|
|
});
|
|
|
|
setCookie(c, `${clientOptions.id}_code_verifier`, codeVerifier, {
|
|
...sessionCookieOptions,
|
|
sameSite: 'lax',
|
|
maxAge: oauthCookieMaxAge,
|
|
});
|
|
|
|
if (redirectPath) {
|
|
setCookie(c, `${clientOptions.id}_redirect_path`, `${state} ${redirectPath}`, {
|
|
...sessionCookieOptions,
|
|
sameSite: 'lax',
|
|
maxAge: oauthCookieMaxAge,
|
|
});
|
|
}
|
|
|
|
return c.json({
|
|
redirectUrl: url.toString(),
|
|
});
|
|
};
|