Skip to content

Commit 4945ba1

Browse files
hfivasilov
andauthored
feat: add asymmetric JWT UI (supabase#36519)
* original files from previous PR * get rid of router in jwt-secrets to make it show up * rename jwt-secrets page to jwt-signing-keys * add jwt-signing-keys query * add legacy jwt signing keys query * wire-up JwtSecretKeysTable with queries * add jwt signing keys page to settings menu * deduplicate labels, descriptions, etc * add create, update jwt-signing-key mutations * update types * remove unused components, to be refactored later * make everything into a mostly working state * legacy migration added * put jwt keys page like api keys * fully migrate legacy jwt secret page * fix prettier * fix typecheck ts-expect-error * rm unneeded file * Fix compile errors. * Rename the files and move them to the same folder. * Merge the two constant files. * Fix the imports. * Fix a bug in the API keys page when opening it in a new tab. * Change the page to be at /signing-keys * Fix some minor types. * Break apart some of the components in the signing keys UI. * Use a feature banner for the initial action. * Make a create key dialog and move functionality there. * Fix some cosmetic issues. * Minor cosmetic fixes. * Remove extra keys in RQ cache. * Add a missing link * Add a banner when the feature flag is false. * Minor type fix. * more tiny type fix * fix error on create standby key * add alert to prevent revoking legacy jwt secret without disabling legacy api keys first --------- Co-authored-by: Ivan Vasilov <[email protected]>
1 parent 7960046 commit 4945ba1

32 files changed

+2824
-113
lines changed

apps/studio/components/interfaces/APIKeys/ApiKeysIllustrations.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ExternalLink, Github, Mail } from 'lucide-react'
1+
import { ExternalLink, Github } from 'lucide-react'
22

33
import { LOCAL_STORAGE_KEYS } from 'common'
44
import { FeatureBanner } from 'components/ui/FeatureBanner'
@@ -119,7 +119,13 @@ export const ApiKeysComingSoonBanner = () => {
119119
</p>
120120
<div className="mt-4">
121121
<Button type="default" icon={<Github />}>
122-
Learn more
122+
<a
123+
href="https://github.com/orgs/supabase/discussions/29260"
124+
target="_blank"
125+
rel="noreferrer"
126+
>
127+
Learn more
128+
</a>
123129
</Button>
124130
</div>
125131
</div>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
export interface AlgorithmDetail {
2+
name: string
3+
description: string
4+
pros: string[]
5+
cons: string[]
6+
label: string
7+
shortDescription: string
8+
links: { url: string; label: string }[]
9+
}
10+
11+
export const algorithmDetails: Record<string, AlgorithmDetail> = {
12+
HS256: {
13+
label: 'HS256 (Symmetric)',
14+
name: 'HMAC with SHA-256',
15+
description: 'Symmetric algorithm using a shared secret key',
16+
pros: [
17+
'Fast and simple to use',
18+
'Requires less computational power',
19+
'Suitable for server-to-server communication',
20+
],
21+
cons: [
22+
'Requires secure key exchange',
23+
"Not suitable when the verifier shouldn't be able to sign tokens",
24+
'Key needs to be kept secret on both sides',
25+
],
26+
shortDescription: 'HMAC with SHA-256: Fast, simple, requires secure key exchange',
27+
links: [
28+
{ url: 'https://jwt.io/introduction', label: 'JWT.io Introduction' },
29+
{
30+
url: 'https://datatracker.ietf.org/doc/html/rfc7518#section-3.2',
31+
label: 'RFC 7518 Specification',
32+
},
33+
],
34+
},
35+
RS256: {
36+
label: 'RSA 2048',
37+
name: 'RSA with SHA-256',
38+
description: 'Asymmetric algorithm using a public/private key pair',
39+
pros: [
40+
'Allows public key to be distributed freely',
41+
'Private key can be kept secret on the signing side',
42+
"Suitable for scenarios where the verifier shouldn't be able to sign tokens",
43+
],
44+
cons: [
45+
'Slower than HS256',
46+
'Requires more computational power',
47+
'Keys are larger than ECDSA keys',
48+
],
49+
shortDescription: 'RSA with SHA-256: Allows public key distribution, slower',
50+
links: [
51+
{ url: 'https://jwt.io/introduction', label: 'JWT.io Introduction' },
52+
{
53+
url: 'https://datatracker.ietf.org/doc/html/rfc7518#section-3.3',
54+
label: 'RFC 7518 Specification',
55+
},
56+
],
57+
},
58+
ES256: {
59+
label: 'ECC (P-256)',
60+
name: 'ECDSA with SHA-256',
61+
description: 'Asymmetric algorithm using elliptic curve cryptography',
62+
pros: [
63+
'Faster than RSA',
64+
'Smaller key and signature sizes compared to RSA',
65+
'Provides forward secrecy',
66+
],
67+
cons: [
68+
'Less widely supported than RSA',
69+
'More complex to implement correctly',
70+
'Requires careful implementation to avoid timing attacks',
71+
],
72+
shortDescription: 'ECDSA with SHA-256: Compact keys, fast, modern alternative to RSA',
73+
links: [
74+
{ url: 'https://jwt.io/introduction', label: 'JWT.io Introduction' },
75+
{
76+
url: 'https://datatracker.ietf.org/doc/html/rfc7518#section-3.4',
77+
label: 'RFC 7518 Specification',
78+
},
79+
],
80+
},
81+
}
82+
83+
export const algorithmLabels = Object.keys(algorithmDetails).reduce(
84+
(a, i) => {
85+
a[i] = algorithmDetails[i].label
86+
return a
87+
},
88+
{} as { [name: keyof typeof algorithmDetails]: string }
89+
)
90+
91+
export const algorithmDescriptions = Object.keys(algorithmDetails).reduce(
92+
(a, i) => {
93+
a[i] = algorithmDetails[i].shortDescription
94+
return a
95+
},
96+
{} as { [name: keyof typeof algorithmDetails]: string }
97+
)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { GlobeLock } from 'lucide-react'
2+
import React from 'react'
3+
4+
import { InfoPill } from '../../ui/InfoPill'
5+
import { AlgorithmDetail, algorithmDetails } from './algorithm-details'
6+
7+
interface AlgorithmHoverCardProps {
8+
algorithm: keyof typeof algorithmDetails
9+
legacy?: boolean
10+
}
11+
12+
export const AlgorithmHoverCard: React.FC<AlgorithmHoverCardProps> = ({ algorithm, legacy }) => {
13+
const details: AlgorithmDetail = algorithmDetails[algorithm]
14+
15+
return (
16+
<InfoPill
17+
label={legacy ? `Legacy JWT Secret ${details.label}` : details.label}
18+
icon={<GlobeLock className="w-4" strokeWidth={1} />}
19+
title={details.name}
20+
description={details.description}
21+
links={details.links}
22+
/>
23+
)
24+
}

0 commit comments

Comments
 (0)