<?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>DEV Community: Irwan Phan</title>
    <description>The latest articles on DEV Community by Irwan Phan (@irwanphan).</description>
    <link>https://dev.to/irwanphan</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%2F137488%2Faf41ff4d-ad06-4a37-9489-6780392f2b62.jpeg</url>
      <title>DEV Community: Irwan Phan</title>
      <link>https://dev.to/irwanphan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/irwanphan"/>
    <language>en</language>
    <item>
      <title>Voice News Summary - AI-Powered News Summaries Read Aloud in Seconds with Redis</title>
      <dc:creator>Irwan Phan</dc:creator>
      <pubDate>Sat, 02 Aug 2025 07:46:27 +0000</pubDate>
      <link>https://dev.to/irwanphan/voice-news-summary-ai-powered-news-summaries-read-aloud-in-seconds-with-redis-1lhi</link>
      <guid>https://dev.to/irwanphan/voice-news-summary-ai-powered-news-summaries-read-aloud-in-seconds-with-redis-1lhi</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/redis-2025-07-23"&gt;Redis AI Challenge&lt;/a&gt;: Beyond the Cache&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Voice News Summary solves a common problem: information overload. Reading through dozens of articles every day can be time-consuming, and not everyone has time to skim long news posts. This app lets users type any topic, get an AI-generated summary of the latest news, and listen to it immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;AI-Generated Summaries: Uses OpenAI GPT to produce concise, high-quality summaries.&lt;/li&gt;
&lt;li&gt;Text-to-Speech Output: Converts summaries to natural-sounding voice with ElevenLabs TTS.&lt;/li&gt;
&lt;li&gt;Redis Caching: Speeds up subsequent requests by storing summaries and audio URLs in Redis.&lt;/li&gt;
&lt;li&gt;Serverless Deployment: Built on Next.js and deployed on Vercel for fast, scalable delivery.&lt;/li&gt;
&lt;li&gt;Clean UI: Built with TailwindCSS for a minimal and responsive design.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Frontend: React 19 with Vite, TailwindCSS&lt;/li&gt;
&lt;li&gt;AI APIs: Google Generative AI (for summarization)&lt;/li&gt;
&lt;li&gt;Database &amp;amp; Cache: Redis using ioredis for connection and caching&lt;/li&gt;
&lt;li&gt;Deployment: Vercel (for frontend) + Redis Cloud (for caching &amp;amp; vector storage)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live Demo&lt;/strong&gt;: &lt;a href="https://voice-news-summary.vercel.app" rel="noopener noreferrer"&gt;https://voice-news-summary.vercel.app&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Type any topic, get AI-generated summaries, and listen to them instantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Redis 8
&lt;/h2&gt;

&lt;p&gt;Redis powers the core experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caching Summaries: Once an article summary is generated and converted to audio, it’s stored in Redis for fast future retrieval.&lt;/li&gt;
&lt;li&gt;Redis Vector Sets: Planned future upgrade for semantic search, allowing related news retrieval beyond exact keyword matching.&lt;/li&gt;
&lt;li&gt;Real-time Speed: With Redis Cloud, the app responds in milliseconds, even when handling multiple concurrent requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why It Matters
&lt;/h2&gt;

&lt;p&gt;In a world of &lt;strong&gt;information overload&lt;/strong&gt;, Voice News Summary makes news consumption:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster: Get to the core of a story in seconds.&lt;/li&gt;
&lt;li&gt;Accessible: Listen to summaries instead of reading long text.&lt;/li&gt;
&lt;li&gt;Scalable: Uses AI + Redis to deliver near-instant response times.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What’s Next
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vector Search&lt;/strong&gt;: Use Redis Vector Sets for semantic search and related topic discovery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalized Feeds&lt;/strong&gt;: Customize summaries and voices based on user preferences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile PWA&lt;/strong&gt;: Turn this into a progressive web app for on-the-go usage.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built for the Redis AI Challenge to showcase how Redis can power the next generation of AI-driven, real-time applications.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>redischallenge</category>
      <category>devchallenge</category>
      <category>database</category>
      <category>ai</category>
    </item>
    <item>
      <title>My 30-Day Startup-Style Sprint in a Corporate World</title>
      <dc:creator>Irwan Phan</dc:creator>
      <pubDate>Fri, 01 Aug 2025 03:06:26 +0000</pubDate>
      <link>https://dev.to/irwanphan/my-30-day-startup-style-sprint-in-a-corporate-world-4ea6</link>
      <guid>https://dev.to/irwanphan/my-30-day-startup-style-sprint-in-a-corporate-world-4ea6</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/wlh"&gt;World's Largest Hackathon Writing Challenge&lt;/a&gt;: After the Hack.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One and a half month ago, I joined a company with one mission: manage its online business and develop websites and apps to operate the business lines. It sounded straightforward—but reality had a different plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hands On
&lt;/h3&gt;

&lt;p&gt;I spent my first two weeks digging into the company’s existing assets and resources. The verdict? From my point-of-view, the legacy website was beyond salvage, a chaotic architecture, and a database without any proper model or abstraction. I would say it was a business risk. &lt;/p&gt;

&lt;p&gt;A tough decision had to be made: rebuild from scratch, starting with the main website.&lt;/p&gt;

&lt;h3&gt;
  
  
  “My GitHub Heatmap Looked Like I Was Working Nonstop”
&lt;/h3&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%2Fu4ya4t26whzcc6ijwbyy.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%2Fu4ya4t26whzcc6ijwbyy.png" alt="My Github Heatmap" width="800" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In less than 30 days, I delivered a brand-new full-featured e-commerce platform. My GitHub heatmap looked like I had given up on sleep—and for the most part, I had. But the results were worth it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full-fledged e-commerce with payment gateway integration.&lt;/li&gt;
&lt;li&gt;Dynamic shipping costs&lt;/li&gt;
&lt;li&gt;Mapbox integration for store and pickup point locations.&lt;/li&gt;
&lt;li&gt;New routing with permanent redirection from the legacy site for SEO continuity.&lt;/li&gt;
&lt;li&gt;Dynamic admin panel to manage SEO, product validation, data imports, and multi-role workflows across departments, etc.&lt;/li&gt;
&lt;/ul&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%2Finykf5wc0l2ovminy6pc.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%2Finykf5wc0l2ovminy6pc.png" alt="Screenshot Of Business Settings Page" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Going Live Too Soon, Testing Left Behind
&lt;/h3&gt;

&lt;p&gt;The biggest challenge wasn’t technical—it was time. Barely two weeks into development, I was asked to go live immediately. Standard practices like unit testing, integration testing, usability testing, UAT, penetration testing, and stress testing? Forget it. The stakeholder doesn't hold it as important. They were skipped, and I couldn't argue otherwise.&lt;/p&gt;

&lt;p&gt;I asked my good friend to help me setup and config server on AWS, and it's live on day-27. Just three days after going live, I continue to debug critical transaction workflow bugs—in production.&lt;/p&gt;

&lt;p&gt;Knowing that the old website had been attacked daily and frequently went down, I also implemented honeypots, bot prevention, and extra security layers in record time.&lt;/p&gt;

&lt;h3&gt;
  
  
  “We Are Going To Launch The Next Business in 10 Days.”
&lt;/h3&gt;

&lt;p&gt;While still debugging the first site, I was already asked to deliver the second one in another 10 days. The workload skyrocketed, and burnout and anxiety started creeping in. But maybe I'll share that story on another time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflection, A Step Back, My POV
&lt;/h2&gt;

&lt;p&gt;This experience felt like running a startup sprint—inside a corporate environment. It taught me that technical skills alone aren’t enough. Managing expectations, negotiating deadlines, and balancing quality vs. speed are just as important.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agility matters, but sustainability matters more. Shipping fast is exciting, but doing it repeatedly without proper planning leads to burnout.&lt;/li&gt;
&lt;li&gt;Security is non-negotiable. An insecure product isn’t just a technical risk—it’s a business risk.&lt;/li&gt;
&lt;li&gt;Team culture matters. Doing everything alone is doable for a short sprint, but building a product—and a career—requires building teams and processes. But onboarding people and team building with a super-tight schedule is too scary and not a feasible option for me.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I’m to scale this experience into a repeatable, sustainable development model—one that balances speed, quality, and personal well-being. The steps would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building a small, trusted team to handle future projects. I do have that one and some most trusted buddies. But they're currently not with me on this project.&lt;/li&gt;
&lt;li&gt;Developing templates and reusable modules for faster, safer deployments.&lt;/li&gt;
&lt;li&gt;Sharing more about these lessons so others don’t have to learn them the hard way.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  One more thought
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Sometimes the hack isn’t in the code—it’s in how we manage time, energy, and expectations.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And of course, thanks to AI, I was able to &lt;strong&gt;minimize downtime and reduce wasted thinking time&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
It wasn’t just about writing code faster—it was about having a technical assistant on-demand:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suggesting architecture decisions
&lt;/li&gt;
&lt;li&gt;Helping me debug faster
&lt;/li&gt;
&lt;li&gt;Generating boilerplate code in seconds instead of hours
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  What about you?
&lt;/h4&gt;

&lt;p&gt;Have you ever had to ship something &lt;strong&gt;like this&lt;/strong&gt;? How did you handle it? Let’s talk in the comments.  &lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>wlhchallenge</category>
      <category>career</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Getting Started With Git? A Complete Git Beginner.</title>
      <dc:creator>Irwan Phan</dc:creator>
      <pubDate>Wed, 15 Mar 2023 09:16:29 +0000</pubDate>
      <link>https://dev.to/irwanphan/getting-started-with-git-a-complete-git-beginner-5cfe</link>
      <guid>https://dev.to/irwanphan/getting-started-with-git-a-complete-git-beginner-5cfe</guid>
      <description>&lt;p&gt;I try to recall my first time using git. I was not a tech-guy back then, not even close. Pencil, Pen, and Photoshop was my daily tools back then. &lt;/p&gt;

&lt;p&gt;Later I jumped into web development. When my peer told me about collaboration using git, it overwhelmed me with command-line-stuff. I thought it was a really complicated stuff. But my peer just gave me some simple commands for daily use. And I only use those some-simple lines until now, except sometimes-unexpected things happened.&lt;/p&gt;

&lt;p&gt;I am writing these down, since I had to share how to use git to my class. And I just gonna &lt;strong&gt;skip&lt;/strong&gt; the complicated parts. Hope it helps&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Git, If It's Not Installed Yet
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gHgD1a0Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/33zwa9kth7xu7nt8ynzc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gHgD1a0Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/33zwa9kth7xu7nt8ynzc.png" alt="Site to Download Git" width="880" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Download the installer from &lt;a href="https://git-scm.com/download/win"&gt;https://git-scm.com/download/win&lt;/a&gt;, ran the installer, and if you don't understand anything the provided options presented, just go with the default.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Git
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_tUiUApU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kglfu8hocxjrs73q4y2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_tUiUApU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kglfu8hocxjrs73q4y2n.png" alt="Terminal in VSCode" width="880" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Git commands can be directly used from VSCode terminal, you can open the terminal by pressing &lt;strong&gt;Ctrl&lt;/strong&gt; + &lt;strong&gt;Shift&lt;/strong&gt; + &lt;strong&gt;`&lt;/strong&gt;. Or you can open it from the top menu &lt;strong&gt;Terminal&lt;/strong&gt;, then choose &lt;strong&gt;New Terminal&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  If It Is An Existing Repository
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Clone The Repo
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LlcCro6s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9rf2lixpmz7f0r20hvwv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LlcCro6s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9rf2lixpmz7f0r20hvwv.png" alt="Github Repository" width="880" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If-it is an existing Repository, go to the repository on Github, click the &lt;strong&gt;"Code"&lt;/strong&gt; button, and copy the git url (you can just click the right side button). then go back to the terminal and type &lt;strong&gt;git clone&lt;/strong&gt; command like this. (using the developer-roadmap repo as example)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
git clone https://github.com/kamranahmedse/developer-roadmap.git&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Config - One time only
&lt;/h4&gt;

&lt;p&gt;This command actually write the config file inside the hidden .git folder. We'll skip it, just remember that you can always re-config using this command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
git config user.email "tapas@someemail.com"&lt;br&gt;
git config user.name "Irwan Phan"&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Add and Commit Changes
&lt;/h4&gt;

&lt;p&gt;To add the files changed to staging, we use the &lt;strong&gt;git add&lt;/strong&gt; command follow by file name or directory/folder name. But we can also just add all the changed files by using . like below.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
git add .&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The next thing to do after added the changes to staging area is to commit it using &lt;strong&gt;git commit&lt;/strong&gt; command, and remember to always makes the commit title as clear as possible.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
git commit -m "change the x part with x2y"&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Push To Repo (Remote Repository)
&lt;/h4&gt;

&lt;p&gt;Push the committed changes to the remote repo by using &lt;strong&gt;git push&lt;/strong&gt; command follow by &lt;strong&gt;remote&lt;/strong&gt; and branch name, e.g &lt;strong&gt;main&lt;/strong&gt;. If it's a cloned repository, you'll only need to type &lt;strong&gt;git push&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
git push&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  If It Is A New Repository
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Initiate A Repo
&lt;/h4&gt;

&lt;p&gt;To create a new repository, we can use the &lt;strong&gt;git init&lt;/strong&gt; command followed by repository name, or just &lt;strong&gt;git init&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
git init repo-name&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Config
&lt;/h4&gt;

&lt;p&gt;Use &lt;strong&gt;git config&lt;/strong&gt; for user name and email used in your Github like mentioned in step #2 above.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
git config user.email "tapas@someemail.com"&lt;br&gt;
git config user.name "Irwan Phan"&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Add And Commit Changes
&lt;/h4&gt;

&lt;p&gt;Use &lt;strong&gt;git add&lt;/strong&gt; to add to staging and &lt;strong&gt;git commit&lt;/strong&gt; to commit the changes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
git add .&lt;br&gt;
git commit -m "change the x part with x2y"&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Push To Repo (Remote Repository)
&lt;/h4&gt;

&lt;p&gt;To push to a new remote repository use &lt;strong&gt;git push_ command followed by __-u&lt;/strong&gt;, &lt;strong&gt;remote&lt;/strong&gt;, and branch name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
git push -u remote main&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapped
&lt;/h3&gt;

&lt;p&gt;I hope this note could be of help for anyone. I tried to make it as simple as possible. For more information on how to use git, you can visit here &lt;a href="https://training.github.com/downloads/github-git-cheat-sheet/"&gt;https://training.github.com/downloads/github-git-cheat-sheet/&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>git</category>
      <category>howto</category>
      <category>windows</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Implement Sign in with Google using Supabase Auth in NextJS</title>
      <dc:creator>Irwan Phan</dc:creator>
      <pubDate>Sun, 26 Feb 2023 08:32:07 +0000</pubDate>
      <link>https://dev.to/irwanphan/implement-sign-in-with-google-using-supabase-auth-in-nextjs-1jj1</link>
      <guid>https://dev.to/irwanphan/implement-sign-in-with-google-using-supabase-auth-in-nextjs-1jj1</guid>
      <description>&lt;p&gt;I'm writing this as my personal documentation also, because I was having a hard time when I tried re-implementing this in another project. Feels free to give me advice for better way to implement this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get Your Google Credential
&lt;/h3&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%2Fezg2uj5xk8i7vdybhpww.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%2Fezg2uj5xk8i7vdybhpww.png" alt="Get Google Credential" width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First of all, sign in to cloud.google.com. &lt;/li&gt;
&lt;li&gt;Create or select a project&lt;/li&gt;
&lt;li&gt;Go to APIs &amp;amp; Services, Credentials&lt;/li&gt;
&lt;li&gt;Create Credentials, and pick OAuth client ID&lt;/li&gt;
&lt;li&gt;Copy the CLIENT_ID and CLIENT_SECRET to your local .env or note&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Enter Google Credentials On Supabase
&lt;/h3&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%2Fxhb93e2r9mcx6femnj1i.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%2Fxhb93e2r9mcx6femnj1i.png" alt="Google Auth Provider in Supabase" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to your Supabase project, on the left menu pick Authentication&lt;/li&gt;
&lt;li&gt;On menu Providers, look for Google, then enable it&lt;/li&gt;
&lt;li&gt;Paste Google's CLIENT_ID and CLIENT_SECRET then hit save&lt;/li&gt;
&lt;li&gt;Copy the redirect URL and paste to cloud.google.com project, in your previous Credentials, paste to Authorized redirect URIs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Local ENV
&lt;/h3&gt;

&lt;p&gt;Go to your Supabase Project, to Project Settings, API&lt;br&gt;
copy your Project URL to local ENV and name it SUPABASE_URL&lt;br&gt;
copy your Anon Public Key in Project API Keys to local ENV and name it SUPABASE_ANON_KEY&lt;/p&gt;
&lt;h3&gt;
  
  
  Create a Sign In module
&lt;/h3&gt;

&lt;p&gt;First, install Supabase Client, using npm or yarn&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;supabase&lt;/span&gt;&lt;span class="sr"&gt;/supabase-j&lt;/span&gt;&lt;span class="err"&gt;s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then connect to Supabase, and make sure the URL is available&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@supabase/supabase-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabaseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabaseAnonKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_ANON_KEY&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;supabaseUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Supabase URL not found.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;supabaseAnonKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Supabase Anon key not found.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supabaseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;supabaseAnonKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I create a connections folder and create a signIn.ts file inside, for first test run, I do not use any options on the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./connections/signIn.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./supabase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;signInWithGoogle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signInWithOAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;google&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// options: {&lt;/span&gt;
        &lt;span class="c1"&gt;//     // redirectTo: getURL() // function to get your URL&lt;/span&gt;
        &lt;span class="c1"&gt;// }&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then create the signOut.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./connections/signOut.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./supabase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signOut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can apply the signInWithGoogle() and the signOut() to your preferable trigger.&lt;br&gt;
here's an example, I am using Chakra-UI, you so the theming with Button was preset in theme and there's the Box element, with the react icon &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%2Fku0xq96v6maq6xbkcbzg.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%2Fku0xq96v6maq6xbkcbzg.png" alt="Login with Google Button" width="615" height="160"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;
    &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Redirecting...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="nf"&gt;signInWithGoogle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Box&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;FcGoogle&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;mr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;fontSize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt;Logi&lt;/span&gt;&lt;span class="err"&gt;n
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F6408795xx6b2z0q5exht.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%2F6408795xx6b2z0q5exht.png" alt="Authenticated Example" width="481" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created a component to replace the button after checking the authentication that shown like above.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>howto</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
