-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat(webapp): app auto session logout #3473
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
6813adf
2bc0b77
83e779d
434ca8f
a3d7239
a719118
fb57aa6
4804b00
5a8b888
96730fa
36ef44f
287f566
8062e16
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import { type ActionFunctionArgs, json } from "@remix-run/server-runtime"; | ||
| import { z } from "zod"; | ||
| import { prisma } from "~/db.server"; | ||
| import { requireAdminApiRequest } from "~/services/personalAccessToken.server"; | ||
|
|
||
| const ParamsSchema = z.object({ | ||
| organizationId: z.string(), | ||
| }); | ||
|
|
||
| const RequestBodySchema = z.object({ | ||
| /** | ||
| * Maximum session lifetime (seconds) for members of this organization, or | ||
| * null to remove the cap. When set, this caps each member's | ||
| * `User.sessionDuration` and is enforced on the user's next request. | ||
| */ | ||
| maxSessionDuration: z.number().int().positive().nullable(), | ||
| }); | ||
|
|
||
| export async function action({ request, params }: ActionFunctionArgs) { | ||
| await requireAdminApiRequest(request); | ||
|
|
||
| const { organizationId } = ParamsSchema.parse(params); | ||
| const body = RequestBodySchema.parse(await request.json()); | ||
|
|
||
| const organization = await prisma.organization.update({ | ||
| where: { id: organizationId }, | ||
| data: { maxSessionDuration: body.maxSessionDuration }, | ||
| select: { id: true, slug: true, maxSessionDuration: true }, | ||
| }); | ||
|
|
||
| return json({ success: true, organization }); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { getSession, redirectWithErrorMessage } from "~/models/message.server"; | |
| import { authenticator } from "~/services/auth.server"; | ||
| import { setLastAuthMethodHeader } from "~/services/lastAuthMethod.server"; | ||
| import { commitSession } from "~/services/sessionStorage.server"; | ||
| import { commitAuthenticatedSession } from "~/services/sessionDuration.server"; | ||
| import { trackAndClearReferralSource } from "~/services/referralSource.server"; | ||
| import { redirectCookie } from "./auth.github"; | ||
| import { sanitizeRedirectPath } from "~/utils"; | ||
|
|
@@ -52,7 +53,7 @@ export let loader: LoaderFunction = async ({ request }) => { | |
| session.set(authenticator.sessionKey, auth); | ||
|
|
||
| const headers = new Headers(); | ||
| headers.append("Set-Cookie", await commitSession(session)); | ||
| headers.append("Set-Cookie", await commitAuthenticatedSession(session)); | ||
|
Comment on lines
53
to
+56
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚩 Auth callbacks commit a __message Session object via __session's commitSession In (Refers to lines 22-56) Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| headers.append("Set-Cookie", await setLastAuthMethodHeader("github")); | ||
|
|
||
| await trackAndClearReferralSource(request, auth.userId, headers); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,24 +12,24 @@ interface MfaToggleProps { | |
| export function MfaToggle({ isEnabled, onToggle }: MfaToggleProps) { | ||
| return ( | ||
| <Form method="post" className="w-full"> | ||
| <InputGroup className="mb-4"> | ||
| <Label>Multi-factor authentication</Label> | ||
| <Paragraph variant="small"> | ||
| Enable an extra layer of security by requiring a one-time code from your authenticator | ||
| app (TOTP) each time you log in. | ||
| </Paragraph> | ||
| </InputGroup> | ||
| <div className="flex items-center justify-between"> | ||
| <Switch | ||
| id="mfa" | ||
| variant="medium" | ||
| label={isEnabled ? "Enabled" : "Enable"} | ||
| labelPosition="right" | ||
| className="-ml-2 w-fit pr-3" | ||
| checked={isEnabled} | ||
| onCheckedChange={onToggle} | ||
| /> | ||
| <div className="flex w-full items-center justify-between gap-4"> | ||
| <InputGroup className="flex-1"> | ||
| <Label>Multi-factor authentication</Label> | ||
| <Paragraph variant="small"> | ||
| Require a one-time code from your authenticator app (TOTP). | ||
| </Paragraph> | ||
| </InputGroup> | ||
| <div className="flex flex-none items-center"> | ||
| <Switch | ||
| id="mfa" | ||
| variant="medium" | ||
| labelPosition="right" | ||
| className="w-fit pr-3" | ||
| checked={isEnabled} | ||
| onCheckedChange={onToggle} | ||
| /> | ||
|
Comment on lines
+23
to
+30
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Switch may no longer have an accessible name. On Line 23-30, Suggested fix- <Label>Multi-factor authentication</Label>
+ <Label id="mfa-label">Multi-factor authentication</Label>
<Paragraph variant="small">
Require a one-time code from your authenticator app (TOTP).
</Paragraph>
@@
<Switch
id="mfa"
+ aria-labelledby="mfa-label"
variant="medium"
labelPosition="right"
className="w-fit pr-3"
checked={isEnabled}
onCheckedChange={onToggle}
/>🤖 Prompt for AI Agents |
||
| </div> | ||
| </div> | ||
| </Form> | ||
| ); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle non-existent organization gracefully.
If
organizationIddoesn't exist,prisma.organization.updatethrows a PrismaP2025error, resulting in an unhandled 500. Consider catching this or checking existence first to return a proper 404.🛡️ Proposed fix
🤖 Prompt for AI Agents