Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2021,6 +2021,7 @@ export const platform: NavMenuConstant = {
{ name: 'Compute and Disk', url: '/guides/platform/compute-and-disk' },
{ name: 'Database Size', url: '/guides/platform/database-size' },
{ name: 'Fly Postgres', url: '/guides/platform/fly-postgres' },
{ name: 'HIPAA Projects', url: '/guides/platform/hipaa-projects' },
{
name: 'Network Restrictions',
url: '/guides/platform/network-restrictions',
Expand Down
10 changes: 10 additions & 0 deletions apps/docs/content/guides/auth/auth-identity-linking.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,13 @@ if google_identity:

</TabPanel>
</Tabs>

## Frequently asked questions

### How to add email/password login to an OAuth account?

Call the `updateUser({ password: 'validpassword'})` to add email with password authentication to an account created with an OAuth provider (Google, GitHub, etc.).

### Can you sign up with email if already using OAuth?

If you try to create an email account after previously signing up with OAuth using the same email, you'll receive an obfuscated user response with no verification email sent. This prevents user enumeration attacks.
28 changes: 28 additions & 0 deletions apps/docs/content/guides/platform/hipaa-projects.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
id: 'hipaa'
title: 'HIPAA Projects'
description: 'Projects that store or process Protected Health Information (PHI) and other sensitive data'
---

You can use Supabase to store and process Protected Health Information (PHI). If you want to start developing healthcare apps on Supabase, reach out to the Supabase team [here](https://forms.supabase.com/hipaa2) to sign the Business Associate Agreement (BAA).

<Admonition type="note">

Organizations must have a signed BAA with Supabase and have the Health Insurance Portability and Accountability Act (HIPAA) add-on enabled when dealing with PHI.

</Admonition>

## Configuring a HIPAA Project

When the HIPAA add-on is enabled on an organization, projects within the organization can be configured as _High Compliance_. This configuration can be found in the [General Project Settings page](https://supabase.com/dashboard/project/_/settings) of the dashboard.
Once enabled, additional security checks will be run against the project to ensure the deployed configuration is compliant. These checks are performed on a continual basis and security warnings will appear in the [Security Advisor](https://supabase.com/dashboard/project/_/advisors/security) if a non-compliant setting is detected.

The required project configuration is outlined in the [shared responsibility model](https://supabase.com/docs/guides/deployment/shared-responsibility-model#managing-healthcare-data) for managing healthcare data.

These include:

- Enabling [Point in Time Recovery](/docs/guides/platform/backups#point-in-time-recovery) which requires at least a [small compute add-on](/docs/guides/platform/compute-add-ons).
- Turning on [SSL Enforcement](/docs/guides/platform/ssl-enforcement).
- Enabling [Network Restrictions](/docs/guides/platform/network-restrictions).

Additional security checks and controls will be added as the security advisor is extended and additional security controls are made available.
1 change: 1 addition & 0 deletions apps/docs/public/humans.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Kevin Brolly
Kevin Grüneberg
Lakshan Perera
Laura C
Laurence Isla
Long Hoang
Łukasz Niemier
Margarita Sandomirskaia
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import Link from 'next/link'

import { useParams } from 'common'
import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, WarningIcon } from 'ui'
import {
AlertDescription_Shadcn_,
AlertTitle_Shadcn_,
Alert_Shadcn_,
Button,
WarningIcon,
} from 'ui'

export function EmailRateLimitsAlert() {
const { ref: projectRef } = useParams()
const after20240926 = Date.now() >= new Date('20240926T00:00:00Z').getTime()
const { ref } = useParams()

return (
<Alert_Shadcn_ variant="warning">
Expand All @@ -14,30 +19,21 @@ export function EmailRateLimitsAlert() {
<AlertDescription_Shadcn_>
You're using the built-in email service. The service has rate limits and it's not meant to
be used for production apps. Check the{' '}
{/* [Refactor] Swap for InlineLink component once https://github.com/supabase/supabase/pull/30494 is in */}
<a
href="https://supabase.com/docs/guides/platform/going-into-prod#auth-rate-limits"
className="underline"
target="_blank"
rel="noreferrer noopener"
>
documentation
</a>{' '}
for an up-to-date information on the current rate limits.{' '}
<Link
className="underline"
target="_blank"
href={`/project/${projectRef}/settings/auth#auth-config-smtp-form`}
>
Set up a custom SMTP server now.
</Link>
</AlertDescription_Shadcn_>
<AlertDescription_Shadcn_ className="mt-2">
{after20240926
? 'To fight abuse, Auth email messages are restricted '
: 'On 26th September: To fight abuse, Auth email messages will be restricted '}
to your project's organization members. For example, if your organization has 3 members with
addresses: <code>[email protected]</code>, <code>[email protected]</code> and{' '}
<code>[email protected]</code>, messages will be{' '}
<strong>sent to those addresses only.</strong> Set up custom SMTP to send to any user.
for an up-to-date information on the current rate limits.
<Button asChild type="default" className="mt-2">
<Link target="_blank" href={`/project/${ref}/settings/auth#auth-config-smtp-form`}>
Set up custom SMTP server
</Link>
</Button>
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { FormHeader } from 'components/ui/Forms/FormHeader'
import { FormPanel } from 'components/ui/Forms/FormPanel'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
import { Tabs, Tabs_Shadcn_, TabsContent_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_ } from 'ui'
import { Tabs_Shadcn_, TabsContent_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_ } from 'ui'
import { TEMPLATES_SCHEMAS } from '../AuthTemplatesValidation'
import EmailRateLimitsAlert from '../EmailRateLimitsAlert'
import TemplateEditor from './TemplateEditor'
Expand Down Expand Up @@ -39,7 +39,11 @@ const EmailTemplates = () => {
{isError && (
<AlertError error={authConfigError} subject="Failed to retrieve auth configuration" />
)}
{isLoading && <GenericSkeletonLoader />}
{isLoading && (
<div className="w-[854px]">
<GenericSkeletonLoader />
</div>
)}
{isSuccess && (
<FormPanel>
<Tabs_Shadcn_ defaultValue={TEMPLATES_SCHEMAS[0].title.trim().replace(/\s+/g, '-')}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { Loader2 } from 'lucide-react'
import { useEffect, useState } from 'react'
import { toast } from 'sonner'

import { useParams } from 'common'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import { DocsButton } from 'components/ui/DocsButton'
import { FormHeader } from 'components/ui/Forms/FormHeader'
import { FormPanel } from 'components/ui/Forms/FormPanel'
import { FormSection, FormSectionContent, FormSectionLabel } from 'components/ui/Forms/FormSection'
import { useComplianceConfigUpdateMutation } from 'data/config/project-compliance-config-mutation'
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { Switch, TooltipContent_Shadcn_, TooltipTrigger_Shadcn_, Tooltip_Shadcn_ } from 'ui'
import AlertError from 'components/ui/AlertError'
import { InlineLink } from 'components/ui/InlineLink'

const ComplianceConfig = () => {
const { ref } = useParams()
const { project } = useProjectContext()
const [isSensitive, setIsSensitive] = useState(false)

const canUpdateComplianceConfig = useCheckPermissions(PermissionAction.UPDATE, 'projects', {
resource: { project_id: project?.id },
})

const {
data: settings,
error,
isError,
isLoading,
isSuccess,
} = useProjectSettingsV2Query({ projectRef: ref })
const initialIsSensitive = settings?.is_sensitive || false

const { mutate: updateComplianceConfig, isLoading: isSubmitting } =
useComplianceConfigUpdateMutation({
onSuccess: () => {
toast.success('Successfully updated project compliance configuration')
},
onError: (error) => {
setIsSensitive(initialIsSensitive)
toast.error(`Failed to update project compliance configuration: ${error.message}`)
},
})

const toggleIsSensitive = async () => {
if (!ref) return console.error('Project ref is required')
setIsSensitive(!isSensitive)
updateComplianceConfig({ projectRef: ref, isSensitive: !isSensitive })
}

useEffect(() => {
if (!isLoading) setIsSensitive(initialIsSensitive)
}, [isLoading])

return (
<div id="compliance-configuration">
<div className="flex items-center justify-between mb-6">
<FormHeader
className="mb-0"
title="High Compliance Configuration"
description="For projects storing and processing sensitive data (HIPAA)"
/>
<DocsButton href="https://supabase.com/docs/guides/platform/hipaa-projects" />
</div>
<FormPanel>
<FormSection
header={
<FormSectionLabel
className="lg:col-span-9"
description={
<p className="text-sm text-foreground-light">
Enable security warnings in the{' '}
<InlineLink href={`/project/${ref}/advisors/security`}>
Security Advisor
</InlineLink>{' '}
to enforce requirements for managing sensitive data
</p>
}
>
Apply additional compliance controls to project
</FormSectionLabel>
}
>
<FormSectionContent loading={false} className="lg:!col-span-3">
<div className="flex items-center justify-end mt-2.5 space-x-2">
{(isLoading || isSubmitting) && (
<Loader2 className="animate-spin" strokeWidth={1.5} size={16} />
)}
{isError && (
<AlertError error={error} subject="Failed to retrieve project settings" />
)}
{isSuccess && (
<Tooltip_Shadcn_>
<TooltipTrigger_Shadcn_ asChild>
{/* [Joshen] Added div as tooltip is messing with data state property of toggle */}
<div>
<Switch
size="large"
checked={isSensitive}
disabled={isLoading || isSubmitting || !canUpdateComplianceConfig}
onCheckedChange={toggleIsSensitive}
/>
</div>
</TooltipTrigger_Shadcn_>
{!canUpdateComplianceConfig && (
<TooltipContent_Shadcn_ side="bottom" className="w-64 text-center">
You need additional permissions to update the compliance configuration for
your project
</TooltipContent_Shadcn_>
)}
</Tooltip_Shadcn_>
)}
</div>
</FormSectionContent>
</FormSection>
</FormPanel>
</div>
)
}

export default ComplianceConfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export { default as DeleteProjectPanel } from './DeleteProjectPanel/DeleteProjec
export { default as DeleteProjectButton } from './DeleteProjectPanel/DeleteProjectButton'
export { default as TransferProjectButton } from './TransferProjectPanel/TransferProjectButton'
export { default as TransferProjectPanel } from './TransferProjectPanel/TransferProjectPanel'
export { default as ComplianceConfig } from './ComplianceConfig/ProjectComplianceMode'
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ProjectAPIDocs from 'components/interfaces/ProjectAPIDocs/ProjectAPIDocs'
import { AIAssistantPanel } from 'components/ui/AIAssistantPanel/AIAssistantPanel'
import AISettingsModal from 'components/ui/AISettingsModal'
import { Loading } from 'components/ui/Loading'
import ResourceExhaustionWarningBanner from 'components/ui/ResourceExhaustionWarningBanner/ResourceExhaustionWarningBanner'
import { ResourceExhaustionWarningBanner } from 'components/ui/ResourceExhaustionWarningBanner/ResourceExhaustionWarningBanner'
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
import { withAuth } from 'hooks/misc/withAuth'
Expand Down
23 changes: 23 additions & 0 deletions apps/studio/components/ui/InlineLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Link from 'next/link'
import { PropsWithChildren } from 'react'

interface InlineLinkProps {
href: string
}

export const InlineLink = ({ href, children }: PropsWithChildren<InlineLinkProps>) => {
const className =
'underline transition underline-offset-2 decoration-foreground-lighter hover:decoration-foreground'
if (href.startsWith('http')) {
return (
<a className={className} href={href} target="_blank" rel="noreferrer noopener">
{children}
</a>
)
}
return (
<Link className={className} href={href}>
{children}
</Link>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ interface ResourceWarningMessage {
bannerContent: {
warning: { title: string; description: string }
critical: { title?: string; description?: string }
allowDismissable?: boolean
}
cardContent: {
warning: { title: string; description: string }
Expand Down Expand Up @@ -213,36 +212,4 @@ export const RESOURCE_WARNING_MESSAGES: Record<string, ResourceWarningMessage> =
buttonText: 'Check usage',
metric: null,
},
// [Joshen] We can remove this once auth team gives the signal to
auth_restricted_email_sending: {
restrictToRoutes: ['/project/[ref]/auth', '/project/[ref]/settings/auth'], // project home, auth, settings
bannerContent: {
warning: {
title: "Authentication emails are only sent to organization members' email addresses",
description:
'Set up a custom SMTP provider to handle flows like password reset which require sending emails to any user',
},
critical: {
title: "Authentication emails are only sent to organization members' email addresses",
description:
'Set up a custom SMTP provider to handle flows like password reset which require sending emails to any user',
},
allowDismissable: true,
},
cardContent: {
warning: {
title: 'Auth emails are restricted',
description:
"Your project can only send Auth emails to your organization's members. Set up a custom SMTP provider to send Auth emails to any user",
},
critical: {
title: 'Auth emails are restricted',
description:
"Your project can only send Auth emails to your organization's members. Set up a custom SMTP provider to send Auth emails to any user.",
},
},
docsUrl: 'https://github.com/orgs/supabase/discussions/29370',
buttonText: 'Set up custom SMTP now',
metric: 'auth_restricted_email_sending',
},
}
Loading
Loading