mirror of
https://github.com/tale/headplane.git
synced 2026-08-22 10:46:38 +00:00
feat: pkce
This commit is contained in:
@@ -47,7 +47,7 @@ function getErrorMessage(code: string) {
|
||||
case 'error_auth_failed':
|
||||
return (
|
||||
<Card.Text>
|
||||
Authentication with the SSO provider failed. Please tray again later.
|
||||
Authentication with the SSO provider failed. Please try again later.
|
||||
Headplane logs may provide more information.
|
||||
</Card.Text>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { AlertCircle } from 'lucide-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import {
|
||||
data,
|
||||
Form,
|
||||
Link as RemixLink,
|
||||
redirect,
|
||||
@@ -12,7 +11,6 @@ import Card from '~/components/Card';
|
||||
import Code from '~/components/Code';
|
||||
import Input from '~/components/Input';
|
||||
import Link from '~/components/Link';
|
||||
import { OidcConnectorError } from '~/server/web/oidc-connector';
|
||||
import { useLiveData } from '~/utils/live-data';
|
||||
import type { Route } from './+types/page';
|
||||
import { loginAction } from './action';
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
import { count, eq } from 'drizzle-orm';
|
||||
import * as oidc from 'openid-client';
|
||||
import { data, type LoaderFunctionArgs, redirect } from 'react-router';
|
||||
import { data, redirect } from 'react-router';
|
||||
import { ulid } from 'ulidx';
|
||||
import type { LoadContext } from '~/server';
|
||||
import { users } from '~/server/db/schema';
|
||||
import { Roles } from '~/server/web/roles';
|
||||
import log from '~/utils/log';
|
||||
import { createOidcStateCookie } from '~/utils/oidc-state';
|
||||
import type { Route } from './+types/oidc-callback';
|
||||
|
||||
export async function loader({
|
||||
request,
|
||||
context,
|
||||
}: LoaderFunctionArgs<LoadContext>) {
|
||||
export async function loader({ request, context }: Route.LoaderArgs) {
|
||||
if (!context.oidcConnector?.isValid) {
|
||||
throw data('OIDC is not enabled or misconfigured', { status: 501 });
|
||||
}
|
||||
@@ -30,8 +27,8 @@ export async function loader({
|
||||
return redirect('/login?s=error_no_session');
|
||||
}
|
||||
|
||||
const { state, nonce, redirect_uri } = oidcCookieState;
|
||||
if (!state || !nonce || !redirect_uri) {
|
||||
const { state, nonce, redirect_uri, verifier } = oidcCookieState;
|
||||
if (!state || !nonce || !redirect_uri || !verifier) {
|
||||
log.warn('auth', 'OIDC session cookie is missing required fields');
|
||||
return redirect('/login?s=error_invalid_session');
|
||||
}
|
||||
@@ -47,6 +44,9 @@ export async function loader({
|
||||
{
|
||||
expectedState: state,
|
||||
expectedNonce: nonce,
|
||||
...(context.oidcConnector.usePKCE
|
||||
? { pkceCodeVerifier: verifier }
|
||||
: {}),
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import * as oidc from 'openid-client';
|
||||
import { data, type LoaderFunctionArgs, redirect } from 'react-router';
|
||||
import type { LoadContext } from '~/server';
|
||||
import { data, redirect } from 'react-router';
|
||||
import { HeadplaneConfig } from '~/server/config/config-schema';
|
||||
import { createOidcStateCookie } from '~/utils/oidc-state';
|
||||
import type { Route } from './+types/oidc-start';
|
||||
|
||||
export async function loader({
|
||||
request,
|
||||
context,
|
||||
}: LoaderFunctionArgs<LoadContext>) {
|
||||
export async function loader({ request, context }: Route.LoaderArgs) {
|
||||
try {
|
||||
await context.sessions.auth(request);
|
||||
return redirect('/');
|
||||
@@ -21,6 +18,7 @@ export async function loader({
|
||||
const redirect_uri = getRedirectUri(context.config, request);
|
||||
|
||||
const nonce = oidc.randomNonce();
|
||||
const verifier = oidc.randomPKCECodeVerifier();
|
||||
const state = oidc.randomState();
|
||||
|
||||
const url = oidc.buildAuthorizationUrl(context.oidcConnector.client, {
|
||||
@@ -29,6 +27,12 @@ export async function loader({
|
||||
redirect_uri,
|
||||
state,
|
||||
nonce,
|
||||
...(context.oidcConnector.usePKCE
|
||||
? {
|
||||
code_challenge_method: 'S256',
|
||||
code_challenge: await oidc.calculatePKCECodeChallenge(verifier),
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
|
||||
return redirect(url.href, {
|
||||
@@ -37,6 +41,7 @@ export async function loader({
|
||||
'Set-Cookie': await cookie.serialize({
|
||||
state,
|
||||
nonce,
|
||||
verifier,
|
||||
redirect_uri,
|
||||
}),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user