<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Lee Yi Jie Joel</title>
    <description>The latest articles on Forem by Lee Yi Jie Joel (@j0).</description>
    <link>https://forem.com/j0</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F467708%2F3db77168-fbb2-443b-b3ad-ad030c8b7481.jpeg</url>
      <title>Forem: Lee Yi Jie Joel</title>
      <link>https://forem.com/j0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/j0"/>
    <language>en</language>
    <item>
      <title>Integrating FastAPI with Supabase Auth</title>
      <dc:creator>Lee Yi Jie Joel</dc:creator>
      <pubDate>Sun, 05 Mar 2023 16:06:23 +0000</pubDate>
      <link>https://forem.com/j0/integrating-fastapi-with-supabase-auth-780</link>
      <guid>https://forem.com/j0/integrating-fastapi-with-supabase-auth-780</guid>
      <description>&lt;h2&gt;
  
  
  Why this article and what we'll cover
&lt;/h2&gt;

&lt;p&gt;In this article we'll go over the basics of how to implement login and logout functionality using Supabase Auth. We'll also go over how to guard routes so that only signed in users can access protected routes. &lt;/p&gt;

&lt;h3&gt;
  
  
  What is Supabase Auth
&lt;/h3&gt;

&lt;p&gt;Supabase is a JSON Web Token based Auth service - it takes in the credentials of a user (for instance email and password) and returns a token that is used to securely transit information between parties. Other services can then make use of this token to know more about the user. For example, we can determine the user's role as well as the authentication methods that they have used to sign in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a sign up route
&lt;/h3&gt;

&lt;p&gt;If integrating with Supabase Auth, one would simply need to wrap the client library in a route in order to get sign in, sign up, and sign out functionality. Here's an example: &lt;/p&gt;

&lt;p&gt;Initialise a client in a centralised file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
from supabase import create_client, Client

url: str = os.environ.get("SUPABASE_URL")
key: str = os.environ.get("SUPABASE_KEY")
supa: Client = create_client(url, key)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Import the client into your application logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from .supabase import supa

@app.get("/sign_up")
def sign_up():
  res = supa.auth.sign_up(email="testsupa@gmail.com",
                          password="testsupabasenow")
  return res.get("access_token")

@app.get("/sign_out")
def sign_out():
  supa = init_supabase()
  res = supa.auth.sign_out()
  return "success"

@app.get("/sign_in")
def sign_in():
  supa = init_supabase()
  res = supa.auth.sign_in_with_password({"email":"testsupa@gmail.com", "password": "testsupabasenow"})
  return res.get("access_token")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To protect a route, there are two main options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We can write a middleware function to validate the incoming JWT&lt;/li&gt;
&lt;li&gt;We can use an extended version of the default FastAPI HTTPBearer together with Dependency Injection to validate the route&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We're going to go with the second option as it is slightly less verbose. &lt;/p&gt;

&lt;p&gt;Let's extend the built in HTTP Bearer class to decode and validate the JWT.  We can do so by making use of a jwt library like &lt;code&gt;python-jose&lt;/code&gt; or &lt;code&gt;PyJWT&lt;/code&gt;. We'll also need the Supabase JWT secret which is under Settings &amp;gt; Auth at time of writing.&lt;/p&gt;

&lt;h2&gt;
  
  
  JWT Bearer class
&lt;/h2&gt;

&lt;p&gt;Let's extend the built in JWT Bearer - below is a snippet taken from &lt;a href="https://testdriven.io/blog/fastapi-jwt-auth/" rel="noopener noreferrer"&gt;TestDriven.io's blog&lt;/a&gt; which performs a verification of the JWT to ensure that credentials are valid.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class JWTBearer(HTTPBearer):
    def __init__(self, auto_error: bool = True):
        super(JWTBearer, self).__init__(auto_error=auto_error)

    async def __call__(self, request: Request):
        credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
        if credentials:
            if not credentials.scheme == "Bearer":
                raise HTTPException(status_code=403, detail="Invalid authentication scheme.")
            if not self.verify_jwt(credentials.credentials):
                raise HTTPException(status_code=403, detail="Invalid token or expired token.")
            return credentials.credentials
        else:
            raise HTTPException(status_code=403, detail="Invalid authorization code.")

    def verify_jwt(self, jwtoken: str) -&amp;gt; bool:
        isTokenValid: bool = False

        try:
            payload = decodeJWT(jwtoken)
        except:
            payload = None
        if payload:
            isTokenValid = True
        return isTokenValid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to protect the route, we can import the extended HTTP Bearer class and use the dependencies, option in FastAPI to protect the route. &lt;/p&gt;

&lt;p&gt;Here's what it would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from auth import JWTBearer
@app.post('/my-protected-route/',dependencies=[Depends(JWTBearer())], response_model=SchemaJob)
async def job(job: SchemaJob):
    ...
    # Some work here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voila, you have a protected route.With this protection, requests to protected routes will raise an error if the &lt;code&gt;Authorization Bearer: &amp;lt;jwt-token&amp;gt;&lt;/code&gt; header is not included. &lt;/p&gt;

&lt;p&gt;It is also possible to extend this implementation by implementing custom checks based on claims or roles in &lt;code&gt;def __call__&lt;/code&gt; of the &lt;code&gt;JWTBearer&lt;/code&gt; class above. For more information on JWTs, you may wish to check out the &lt;a href="https://supabase.com/docs/learn/auth-deep-dive/auth-deep-dive-jwts" rel="noopener noreferrer"&gt;Supabase website Auth section&lt;/a&gt; for a deeper look into how JWTs function.&lt;/p&gt;

&lt;p&gt;Here's the &lt;a href="https://github.com/J0/fastapi-supabase-auth" rel="noopener noreferrer"&gt;sample repo&lt;/a&gt;. Please feel free to leave any questions in the comments below.&lt;/p&gt;

&lt;p&gt;The example code draws reference from:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://testdriven.io/blog/fastapi-jwt-auth/" rel="noopener noreferrer"&gt;https://testdriven.io/blog/fastapi-jwt-auth/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://educative.io/answers/how-to-use-postgresql-database-in-fastapi" rel="noopener noreferrer"&gt;https://educative.io/answers/how-to-use-postgresql-database-in-fastapi&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>development</category>
      <category>software</category>
      <category>infrastructure</category>
      <category>automation</category>
    </item>
    <item>
      <title>Setting up FastAPI with SupabaseDB</title>
      <dc:creator>Lee Yi Jie Joel</dc:creator>
      <pubDate>Tue, 10 Jan 2023 13:35:24 +0000</pubDate>
      <link>https://forem.com/j0/setting-up-fastapi-with-supabasedb-2jm0</link>
      <guid>https://forem.com/j0/setting-up-fastapi-with-supabasedb-2jm0</guid>
      <description>&lt;h2&gt;
  
  
  What is Supabase?
&lt;/h2&gt;

&lt;p&gt;Supabase is an open source Firebase alternative. It comes with a Postgres database, Authentication, instant APIs, Edge Functions, Realtime subscriptions, and Storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is FastAPI?
&lt;/h2&gt;

&lt;p&gt;FastAPI is a modern, fast (high-performance), web framework for building APIs with Python. It's commonly used to rapidly get an API up and running&lt;/p&gt;

&lt;p&gt;Here we demonstrate how to make use of Supabase as a Postgres Database and connect it to FastAPI so that we can manage migrations. We will make use of Alembic as a migrations versioning tool. This example also heavily draws reference from the &lt;a href="https://fastapi.tiangolo.com/tutorial/sql-databases/" rel="noopener noreferrer"&gt;example provided by FastAPI&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Let's first set up a virtual environment and install some dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;virtualenv .env
pip3 install supabase fastapi psycopg2 alembic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Base Files
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;supafast&lt;/code&gt; directory, create the core files by running &lt;br&gt;
&lt;code&gt;touch app.py __init__.py database.py models.py schema.py&lt;/code&gt;&lt;br&gt;
the key point to note is that &lt;code&gt;models.py&lt;/code&gt; contains &lt;a href="https://docs.pydantic.dev" rel="noopener noreferrer"&gt;pydantic models&lt;/a&gt; while &lt;code&gt;schema.py&lt;/code&gt; contains the &lt;em&gt;database&lt;/em&gt; models which are used to generate the database schema.&lt;/p&gt;
&lt;h2&gt;
  
  
  Populating the models and schema file
&lt;/h2&gt;

&lt;p&gt;Here, we create a users model and schema model so that we can create a users table in the database. The working of both files are best explained by &lt;a href="https://fastapi.tiangolo.com/tutorial/sql-databases/#create-model-attributescolumns" rel="noopener noreferrer"&gt;FastAPI's fantastic tutorial&lt;/a&gt; so please refer there instead.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configure Database URL
&lt;/h3&gt;

&lt;p&gt;Head to &lt;code&gt;SQLALCHEMY_DATABASE_URL&lt;/code&gt; and change the URL to what's found on your Supabase Dashboard (Screenshot of what it looks like at time of writing)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftce7al6a1f1l0o1x7z5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftce7al6a1f1l0o1x7z5w.png" alt="Image description" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;alembic init migrations&lt;/code&gt; to generate a &lt;code&gt;migrations&lt;/code&gt; folder containing all alembic migrations.&lt;/p&gt;
&lt;h3&gt;
  
  
  Linking Database models to Alembic
&lt;/h3&gt;

&lt;p&gt;We need to let Alembic view the FastAPI database models we defined in &lt;code&gt;models.py&lt;/code&gt;. In this case we only have a &lt;code&gt;User&lt;/code&gt; model so let's import that in out &lt;code&gt;migrations/env.py&lt;/code&gt; file by adding&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from supafast.models import User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in &lt;code&gt;migrations/env.py&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating and applying the migrations
&lt;/h3&gt;

&lt;p&gt;From here, we can go ahead and generate an initial migration by running&lt;/p&gt;

&lt;p&gt;&lt;code&gt;alembic revision --autogenerate -m "generate initial migration"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This should create a new version of the migration under &lt;code&gt;migrations/versions/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can then run &lt;code&gt;alembic upgrade head&lt;/code&gt; to apply the migration changes to Supabase DB. Thereafter, we should be able to see the newly created table in the table editor. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrts99mz75czuffk7138.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrts99mz75czuffk7138.png" alt="Image description" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You can find the final state of the source code &lt;a href="https://github.com/J0/supabasedb-fastapi-tutorial" rel="noopener noreferrer"&gt;in this Github repository&lt;/a&gt;. If you prefer a video form of this tutorial you can &lt;a href="https://www.youtube.com/watch?v=6ipV_yAP5I4" rel="noopener noreferrer"&gt;view the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a comprehensive overview of Authentication, Functions, Storage and other items in the Supabase Python SDK, you can also check out &lt;a href="https://www.youtube.com/watch?v=M6cfT2pqpSc" rel="noopener noreferrer"&gt;the Supabase Python Crash Course&lt;/a&gt; kindly put together by Patrick.&lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to leave them in the comments below.&lt;/p&gt;

&lt;p&gt;References:&lt;br&gt;
[1] &lt;a href="https://fastapi.tiangolo.com/tutorial/" rel="noopener noreferrer"&gt;https://fastapi.tiangolo.com/tutorial/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
  </channel>
</rss>
