Skip to content

Commit

Permalink
Merge pull request #83 from digitalservicebund/feat/brak_idp_spike
Browse files Browse the repository at this point in the history
Implemented `/auth/callback` and minor type refactor
  • Loading branch information
Deeds67 authored Jan 7, 2025
2 parents 8d17035 + a5f431d commit 0311b3b
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 45 deletions.
8 changes: 3 additions & 5 deletions .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ fileignoreconfig:
checksum: 3f194ddcbbfc8f9ac2a1655dcd288be0df200b3a285e1c96a5765b9664c1f88d
- filename: .env.example
checksum: e4f39c1718c11d16be854b2ff85c9bfb1d6ea9d5d1fafa3945515b5b458f0dcc
- filename: app/services/brakAuth.server.ts
checksum: d0ed7c5f8143376083b00304d514096728f6455e98aa2dfbe57e260868b28888
- filename: app/config/config.server.ts
checksum: 3e1bcb8f961ca98c3c018e9ea0eb3abbbce7b071f9cf7b0428b7c8be5f29e947
- filename: app/services/oauth.server.ts
checksum: 8adeb6ed54f89b211c51775ef5ee8c7237271b5e791884a9d6691bf24599786c
- filename: app/services/session.server.ts
checksum: 3bd11eb583e1d75872148c2bf127c6eba067084379173b4f53fa83fc5a820cda
checksum: 53b3fb2c0f37f106048ea9bbe6cd4634686ee4035882d3ccedd50b0fd396b83c
- filename: app/services/oauth.server.ts
checksum: c7cf1c465b0a0a4eb5de3d84ea18b60f207ca622d989980cdb27ed9a5cf7a110
version: ""
scopeconfig:
- scope: node
Expand Down
4 changes: 2 additions & 2 deletions app/routes/_index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { data, Link, redirect } from "@remix-run/react";
import { authenticator } from "~/services/oauth.server";
import { AuthenticationProvider, authenticator } from "~/services/oauth.server";

export const meta: MetaFunction = () => {
return [
Expand All @@ -26,7 +26,7 @@ async function authUserRemixOAuth(request: Request) {
if (code) {
try {
let authenticationResponse = await authenticator.authenticate(
"bea",
AuthenticationProvider.BEA,
request,
);
return redirect("/dashboard", {
Expand Down
26 changes: 15 additions & 11 deletions app/routes/auth.callback.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import { data, redirect, type LoaderFunction } from "@remix-run/node";
import { authenticator } from "~/services/oauth.server";
import { redirect, type LoaderFunction } from "@remix-run/node";
import { AuthenticationProvider, authenticator } from "~/services/oauth.server";

// needs to be done on root URL at the moment (redirect_url update needed by BRAK)
export const loader: LoaderFunction = async ({ request }) => {
await authenticator
.authenticate("bea", request)
.then((data) => {
console.log("authorizeUser then", data);
throw redirect("/dashboard");
const authenticationProvider = AuthenticationProvider.BEA;
return authenticator
.authenticate(authenticationProvider, request)
.then((authenticationResponse) => {
return redirect("/dashboard", {
headers: {
"Set-Cookie": authenticationResponse.sessionCookieHeader,
},
});
})
.catch((error) => {
console.log("authorizeUser catch", error);
console.log(
`Failed to authenticate user at : ${authenticationProvider}`,
error,
);
throw redirect("/error");
});

return data(null);
};

export default function AuthCallback() {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/login.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { LoaderFunction } from "@remix-run/node";
import { authenticator } from "~/services/oauth.server";
import { AuthenticationProvider, authenticator } from "~/services/oauth.server";

export const loader: LoaderFunction = async ({ request }) => {
await authenticator.authenticate("bea", request);
await authenticator.authenticate(AuthenticationProvider.BEA, request);
return null;
};
29 changes: 15 additions & 14 deletions app/services/oauth.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ import { Authenticator } from "remix-auth";
import { CodeChallengeMethod, OAuth2Strategy } from "remix-auth-oauth2";
import { config } from "~/config/config.server";
import { createUserSession } from "./session.server";
import { z } from "zod";

export const UserSchema = z.object({
accessToken: z.string(),
expiresAt: z.number(),
});
export interface AuthenticationContext {
accessToken: string;
expiresAt: number;
}

export type User = z.infer<typeof UserSchema>;
export interface AuthenticationResponse {
authenticationContext: AuthenticationContext;
sessionCookieHeader: string; // This is the Set-Cookie header that should be set in the response to the client
}

interface AuthenticatedUserResponse {
user: User;
sessionCookieHeader: string;
export enum AuthenticationProvider {
BEA = "bea",
}

export const authenticator = new Authenticator<AuthenticatedUserResponse>();
export const authenticator = new Authenticator<AuthenticationResponse>();

authenticator.use(
new OAuth2Strategy(
Expand All @@ -32,15 +33,15 @@ authenticator.use(
},
async ({ tokens, request }) => {
const accessToken = tokens.accessToken();
const expiresAt = Date.now() + 60 * 60 * 1000 * 24 * 14;
const expiresAt = Date.now() + 60 * 60 * 1000 * 24 * 14; // 14 days
const sessionCookieHeader = await createUserSession(
accessToken,
expiresAt,
request,
);

const response: AuthenticatedUserResponse = {
user: {
const response: AuthenticationResponse = {
authenticationContext: {
accessToken,
expiresAt,
},
Expand All @@ -50,5 +51,5 @@ authenticator.use(
return response;
},
),
"bea", // name of the strategy. When you call `authenticate`, you pass this name to use this strategy.
AuthenticationProvider.BEA,
);
14 changes: 3 additions & 11 deletions app/services/session.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createCookieSessionStorage, redirect } from "@remix-run/node";
import { config } from "~/config/config.server";
import { User, UserSchema } from "./oauth.server";
import type { AuthenticationContext } from "./oauth.server";

const { getSession, commitSession, destroySession } =
createCookieSessionStorage({
Expand Down Expand Up @@ -33,7 +33,7 @@ export const createUserSession = async (
// We retrieve the user session from the request headers and ensure that the session has not expired.
export const getUserSession = async (
request: Request,
): Promise<User | null> => {
): Promise<AuthenticationContext | null> => {
const session = await getSession(request.headers.get("Cookie"));
const accessToken = session.get("accessToken");
const expiresAt = session.get("expiresAt");
Expand All @@ -43,18 +43,10 @@ export const getUserSession = async (
return null;
}

const user = {
return {
accessToken,
expiresAt,
};

try {
const parsedUser = UserSchema.parse(user);
return parsedUser;
} catch (error) {
console.error("Error parsing user session", error);
return null;
}
};

export const requireUserSession = async (request: Request) => {
Expand Down

0 comments on commit 0311b3b

Please sign in to comment.