Hello!
If you are reading this, please Don’t miss the catch in the end.
The following working supabase edge function was inspired by the great tutorial for Creating an Address Autocomplete feature in a Search Select element in weweb, by ryanenocode here:
This Supabase edge function is called from weweb through the workflow prebuilt action: Invoke Edge Function.
It “replaces” the API call to “https://maps.googleapis.com/maps/api/place/autocomplete/” endpoint used in the tutorial above.
Takes an “input” which is the item searched for; and returns five suggestions for the Autocomplete feature.
The code is produced by GPT4o & Claude together and includes: Checking if the user making the call is logged in (Supabase Auth used), CORS, secure GOOGLE_API_KEY stored in supabase secrets and other stuff the AIs deemed necessary and works.
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { corsHeaders } from '../_shared/cors.ts';
import { createClient } from 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js/+esm';
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_ANON_KEY')!
);
serve(async (req: Request) => {
if (req.method === 'OPTIONS') {
return new Response(null, {
status: 204,
headers: {
...corsHeaders,
'Access-Control-Max-Age': '86400'
}
});
}
try {
const authHeader = req.headers.get('Authorization');
if (!authHeader) {
return new Response(JSON.stringify({ error: 'Missing Authorization header' }), {
status: 401,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
}
const token = authHeader.replace('Bearer ', '');
const { data, error } = await supabase.auth.getUser(token);
if (error || !data.user) {
return new Response(JSON.stringify({ error: 'Invalid or expired token' }), {
status: 401,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
}
const url = new URL(req.url);
const input = url.searchParams.get('input');
console.log('Received input:', input);
if (!input) {
console.log('Missing input parameter');
return new Response(JSON.stringify({ error: 'Missing input parameter' }), {
status: 400,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
}
const apiKey = Deno.env.get('GOOGLE_API_KEY');
if (!apiKey) {
console.log('Missing API key');
return new Response(JSON.stringify({ error: 'Missing API key' }), {
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
}
const apiUrl = new URL('https://maps.googleapis.com/maps/api/place/autocomplete/json');
apiUrl.searchParams.append('input', input);
apiUrl.searchParams.append('key', apiKey);
try {
const apiResponse = await fetch(apiUrl.toString());
const json = await apiResponse.json();
console.log('API response:', json);
return new Response(JSON.stringify(json), {
status: 200,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
} catch (error) {
console.error('Error fetching autocomplete suggestions', error);
return new Response(JSON.stringify({ error: 'Error fetching autocomplete suggestions' }), {
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
}
} catch (error) {
console.error('Unexpected error:', error);
return new Response(JSON.stringify({ error: 'Unexpected error' }), {
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
}
});
CATCH: I have no idea if this is THE secure structure to make API calls (using Supabase Auth & Edge Functions) to places for which weweb has not come up with a Plugin to make them securely for us. It is intended to be the one setup which can be used as a template with the AI’s and various API Documentations to become the go-to tool for the goal.
I kindly ask the community to use this as a working template and come up with the best structure that: even if misses being the overall secure way to call API’s from weweb, which as a scope might leave the confines of this forum, at least become something that exhausts the limits of security weweb can provide as the “initiating party”.
Of course, there is room for Google/recipient call side additions to security such as: api key restrictions, website restrictions etc.
The catch in this case becomes: are all the other forms of securing the process Welcomed Additions OR Imperatives ?
Thank you!
EDIT: my Supabase discord post regarding the same issue so maybe we can work together on this:
EDIT2: Reference of conversations here about the issue for our Supabase visitors who want to get some context