feat: add jwt-decode dependency and implement JWT handling in Supabase security notebook

This commit is contained in:
2026-03-02 14:11:05 -06:00
parent 824db85305
commit 606db3362c
11 changed files with 233 additions and 7 deletions
Generated
+5
View File
@@ -23,6 +23,7 @@
"npm:@toon-format/toon@^2.1.0": "2.1.0",
"npm:@types/bun@^1.3.5": "1.3.5",
"npm:deno@^2.6.4": "2.6.4",
"npm:jwt-decode@4": "4.0.0",
"npm:openai@6.16.0": "6.16.0_zod@3.25.76",
"npm:openai@^4.52.5": "4.104.0_zod@3.25.76",
"npm:openai@^6.16.0": "6.16.0_zod@3.25.76",
@@ -419,6 +420,9 @@
"imurmurhash@0.1.4": {
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="
},
"jwt-decode@4.0.0": {
"integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA=="
},
"math-intrinsics@1.1.0": {
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="
},
@@ -593,6 +597,7 @@
"npm:@toon-format/toon@^2.1.0",
"npm:@types/bun@^1.3.5",
"npm:deno@^2.6.4",
"npm:jwt-decode@4",
"npm:openai@^6.16.0",
"npm:supabase@^2.72.6"
]
+223
View File
@@ -0,0 +1,223 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "3b0acbc3",
"metadata": {},
"outputs": [],
"source": [
"import { createClient } from \"@supabase/supabase-js\";\n",
"const supabaseUrl = Deno.env.get(\"SUPABASE_URL\") || env.SUPABASE_URL;\n",
"const supabaseKey = Deno.env.get(\"SUPABASE_ANON_KEY\") || env.SUPABASE_ANON_KEY;\n",
"\n",
"const supabase = createClient(supabaseUrl, supabaseKey);\n",
"const supa = await supabase.auth.signInWithPassword({\n",
" email: 'guillermo.arrieta@lasalle.mx',\n",
" password: 'admin',\n",
"});"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6ef7e79f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\n",
" access_token: \"eyJhbGciOiJFUzI1NiIsImtpZCI6ImI4MTI2OWYxLTIxZDgtNGYyZS1iNzE5LWMyMjQwYTg0MGQ5MCIsInR5cCI6IkpXVCJ9.eyJhYWwiOiJhYWwxIiwiYW1yIjpbeyJtZXRob2QiOiJwYXNzd29yZCIsInRpbWVzdGFtcCI6MTc3MjQ3MzI3MX1dLCJhcHBfbWV0YWRhdGEiOnsicHJvdmlkZXIiOiJlbWFpbCIsInByb3ZpZGVycyI6WyJlbWFpbCJdfSwiYXVkIjoiYXV0aGVudGljYXRlZCIsImVtYWlsIjoiZ3VpbGxlcm1vLmFycmlldGFAbGFzYWxsZS5teCIsImV4cCI6MTc3MjQ3Njg3MSwiZmVhdHVyZV94Ijp0cnVlLCJpYXQiOjE3NzI0NzMyNzEsImlzX2Fub255bW91cyI6ZmFsc2UsImlzcyI6Imh0dHA6Ly8xMjcuMC4wLjE6NTQzMjEvYXV0aC92MSIsInBob25lIjoiIiwicm9sZSI6ImF1dGhlbnRpY2F0ZWQiLCJzZXNzaW9uX2lkIjoiZjc2ZjRkZGYtZTcxOS00NjRiLWIwYWUtODBhNmIxMjBlZmE0Iiwic3ViIjoiOTVkMWYzODEtNzAyMy00ZjMzLWJjNTQtMDhjY2QwOGFiZjQxIiwidGVuYW50X2lkIjoibG9jYWwtZGV2LXRlbmFudCIsInVzZXJfbWV0YWRhdGEiOnsiZW1haWxfdmVyaWZpZWQiOnRydWV9fQ.LEXrbBNetdCb8zfCiLcXhJg3EmX6XuE4cYOaFmYg1PhvvNI5XorbJQHhb4SQVggQDOauIqqkMRsK64GK1nheIw\",\n",
" token_type: \"bearer\",\n",
" expires_in: 3600,\n",
" expires_at: 1772476871,\n",
" refresh_token: \"lwgtrzw2tpzl\",\n",
" user: {\n",
" id: \"95d1f381-7023-4f33-bc54-08ccd08abf41\",\n",
" aud: \"authenticated\",\n",
" role: \"authenticated\",\n",
" email: \"guillermo.arrieta@lasalle.mx\",\n",
" email_confirmed_at: \"2026-01-13T14:54:39.096101Z\",\n",
" phone: \"\",\n",
" confirmed_at: \"2026-01-13T14:54:39.096101Z\",\n",
" last_sign_in_at: \"2026-03-02T17:41:10.98658403Z\",\n",
" app_metadata: { provider: \"email\", providers: [ \"email\" ] },\n",
" user_metadata: { email_verified: true },\n",
" identities: [\n",
" {\n",
" identity_id: \"b2f3094d-a29b-42b5-be69-3397282ffcd7\",\n",
" id: \"95d1f381-7023-4f33-bc54-08ccd08abf41\",\n",
" user_id: \"95d1f381-7023-4f33-bc54-08ccd08abf41\",\n",
" identity_data: {\n",
" email: \"guillermo.arrieta@lasalle.mx\",\n",
" email_verified: false,\n",
" phone_verified: false,\n",
" sub: \"95d1f381-7023-4f33-bc54-08ccd08abf41\"\n",
" },\n",
" provider: \"email\",\n",
" last_sign_in_at: \"2026-01-13T14:54:39.085382Z\",\n",
" created_at: \"2026-01-13T14:54:39.08544Z\",\n",
" updated_at: \"2026-01-13T14:54:39.08544Z\",\n",
" email: \"guillermo.arrieta@lasalle.mx\"\n",
" }\n",
" ],\n",
" created_at: \"2026-01-13T14:54:39.081453Z\",\n",
" updated_at: \"2026-03-02T17:41:11.002577Z\",\n",
" is_anonymous: false\n",
" },\n",
" weak_password: {\n",
" message: \"Password should be at least 6 characters.\",\n",
" reasons: [ \"length\" ]\n",
" }\n",
"}\n"
]
},
{
"data": {
"text/plain": [
"{\n",
" data: {\n",
" subscription: {\n",
" id: \u001b[32mSymbol(\"auth-callback\")\u001b[39m,\n",
" callback: \u001b[36m[AsyncFunction (anonymous)]\u001b[39m,\n",
" unsubscribe: \u001b[36m[Function: unsubscribe]\u001b[39m\n",
" }\n",
" }\n",
"}"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import { jwtDecode } from \"npm:jwt-decode\";\n",
"\n",
"const listener = supabase.auth.onAuthStateChange(async (event, session) => {\n",
" if (session) {\n",
" const jwt = jwtDecode(session.access_token);\n",
" console.log(event, jwt);\n",
" // store in the session\n",
" localStorage.setItem(\"jwt\", JSON.stringify(session));\n",
" }\n",
"});\n",
"\n",
"listener;\n"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "0471a2d4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\n",
" access_token: \"eyJhbGciOiJFUzI1NiIsImtpZCI6ImI4MTI2OWYxLTIxZDgtNGYyZS1iNzE5LWMyMjQwYTg0MGQ5MCIsInR5cCI6IkpXVCJ9.eyJhYWwiOiJhYWwxIiwiYW1yIjpbeyJtZXRob2QiOiJwYXNzd29yZCIsInRpbWVzdGFtcCI6MTc3MjQ1OTQzMX1dLCJhcHBfbWV0YWRhdGEiOnsicHJvdmlkZXIiOiJlbWFpbCIsInByb3ZpZGVycyI6WyJlbWFpbCJdfSwiYXVkIjoiYXV0aGVudGljYXRlZCIsImVtYWlsIjoiZ3VpbGxlcm1vLmFycmlldGFAbGFzYWxsZS5teCIsImV4cCI6MTc3MjQ3MjAwMywiZmVhdHVyZV94Ijp0cnVlLCJpYXQiOjE3NzI0Njg0MDMsImlzX2Fub255bW91cyI6ZmFsc2UsImlzcyI6Imh0dHA6Ly8xMjcuMC4wLjE6NTQzMjEvYXV0aC92MSIsInBob25lIjoiIiwicm9sZSI6ImF1dGhlbnRpY2F0ZWQiLCJzZXNzaW9uX2lkIjoiMTJkNDc0OGUtNDBiMy00MzQ5LWI0MjUtMWFkNzM2YTk2NTM5Iiwic3ViIjoiOTVkMWYzODEtNzAyMy00ZjMzLWJjNTQtMDhjY2QwOGFiZjQxIiwidGVuYW50X2lkIjoibG9jYWwtZGV2LXRlbmFudCIsInVzZXJfbWV0YWRhdGEiOnsiZW1haWxfdmVyaWZpZWQiOnRydWV9fQ.XbxmaKPEo9Vqr1_W1vuXIaYwGiifaBsaqIwFdJvIuMrFPx5VeW9-NeUasWq3ka1DBsEMWaCFeIKykp9QlvDXqQ\",\n",
" token_type: \"bearer\",\n",
" expires_in: 3600,\n",
" expires_at: 1772472003,\n",
" refresh_token: \"gjdfzz4y4y3v\",\n",
" user: {\n",
" id: \"95d1f381-7023-4f33-bc54-08ccd08abf41\",\n",
" aud: \"authenticated\",\n",
" role: \"authenticated\",\n",
" email: \"guillermo.arrieta@lasalle.mx\",\n",
" email_confirmed_at: \"2026-01-13T14:54:39.096101Z\",\n",
" phone: \"\",\n",
" confirmed_at: \"2026-01-13T14:54:39.096101Z\",\n",
" last_sign_in_at: \"2026-03-02T13:50:31.464916Z\",\n",
" app_metadata: { provider: \"email\", providers: [ \"email\" ] },\n",
" user_metadata: { email_verified: true },\n",
" identities: [\n",
" {\n",
" identity_id: \"b2f3094d-a29b-42b5-be69-3397282ffcd7\",\n",
" id: \"95d1f381-7023-4f33-bc54-08ccd08abf41\",\n",
" user_id: \"95d1f381-7023-4f33-bc54-08ccd08abf41\",\n",
" identity_data: {\n",
" email: \"guillermo.arrieta@lasalle.mx\",\n",
" email_verified: false,\n",
" phone_verified: false,\n",
" sub: \"95d1f381-7023-4f33-bc54-08ccd08abf41\"\n",
" },\n",
" provider: \"email\",\n",
" last_sign_in_at: \"2026-01-13T14:54:39.085382Z\",\n",
" created_at: \"2026-01-13T14:54:39.08544Z\",\n",
" updated_at: \"2026-01-13T14:54:39.08544Z\",\n",
" email: \"guillermo.arrieta@lasalle.mx\"\n",
" }\n",
" ],\n",
" created_at: \"2026-01-13T14:54:39.081453Z\",\n",
" updated_at: \"2026-03-02T16:20:03.535209Z\",\n",
" is_anonymous: false\n",
" }\n",
"}\n"
]
}
],
"source": [
"const raw = localStorage.getItem(\"jwt\")\n",
"const jwt = raw ? JSON.parse(raw) : null\n",
"\n",
"console.log(jwt)"
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "0bfcd412",
"metadata": {},
"outputs": [
{
"ename": "ReferenceError",
"evalue": "useEffect is not defined",
"output_type": "error",
"traceback": [
"Stack trace:",
"ReferenceError: useEffect is not defined",
" at <anonymous>:1:22"
]
}
],
"source": [
"useEffect(() => {\n",
" const onFocus = () => supabase.auth.refreshSession();\n",
" window.addEventListener(\"focus\", onFocus);\n",
" return () => window.removeEventListener(\"focus\", onFocus);\n",
"}, []);"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "88d2d6bc",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Deno",
"language": "typescript",
"name": "deno"
},
"language_info": {
"codemirror_mode": "typescript",
"file_extension": ".ts",
"mimetype": "text/x.typescript",
"name": "typescript",
"nbconvert_exporter": "script",
"pygments_lexer": "typescript",
"version": "5.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
+1
View File
@@ -3,6 +3,7 @@
"@supabase/supabase-js": "^2.90.1",
"@toon-format/toon": "^2.1.0",
"deno": "^2.6.4",
"jwt-decode": "^4.0.0",
"openai": "^6.16.0",
"supabase": "^2.72.6"
},
-1
View File
@@ -1 +0,0 @@
v2.185.0
-1
View File
@@ -1 +0,0 @@
postgresql://postgres.exdkssurzmjnnhgtiama@aws-0-us-west-1.pooler.supabase.com:5432/postgres
-1
View File
@@ -1 +0,0 @@
15.8.1.085
-1
View File
@@ -1 +0,0 @@
exdkssurzmjnnhgtiama
-1
View File
@@ -1 +0,0 @@
v12.2.3
-1
View File
@@ -1 +0,0 @@
buckets-objects-grants-postgres
-1
View File
@@ -1 +0,0 @@
v1.33.0
+4
View File
@@ -48,3 +48,7 @@ entrypoint = "./functions/generate-subject-suggestions/index.ts"
# Specifies static files to be bundled with the function. Supports glob patterns.
# For example, if you want to serve static HTML pages in your function:
# static_files = [ "./functions/generate-subject-suggestions/*.html" ]
[auth.hook.custom_access_token]
enabled = true
uri = "pg-functions://postgres/public/custom_access_token_hook"