<?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: Tanmay Kaushik</title>
    <description>The latest articles on DEV Community by Tanmay Kaushik (@tanmay_kaushik_).</description>
    <link>https://dev.to/tanmay_kaushik_</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%2F2876196%2F620c2aab-94a1-485e-86b3-96922205357b.jpg</url>
      <title>DEV Community: Tanmay Kaushik</title>
      <link>https://dev.to/tanmay_kaushik_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tanmay_kaushik_"/>
    <language>en</language>
    <item>
      <title>Why I Ditched Deep Linking for a Token-Based Password Reset in Supabase</title>
      <dc:creator>Tanmay Kaushik</dc:creator>
      <pubDate>Wed, 19 Feb 2025 16:54:18 +0000</pubDate>
      <link>https://dev.to/tanmay_kaushik_/why-i-ditched-deep-linking-for-a-token-based-password-reset-in-supabase-3e69</link>
      <guid>https://dev.to/tanmay_kaushik_/why-i-ditched-deep-linking-for-a-token-based-password-reset-in-supabase-3e69</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Recently, I was facing a major headache trying to implement a seamless password reset flow using deep linking. The process of managing deep links across various platforms became more complex than I had anticipated, leading to a less-than-ideal user experience.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity Across Platforms:&lt;/strong&gt; Deep linking often requires platform-specific configurations (iOS vs. Android) that can lead to inconsistent behavior, whereas OTP-based resets use a uniform process via email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Risks:&lt;/strong&gt; Improperly managed deep links can expose vulnerabilities, while OTPs are time-sensitive and randomly generated, offering a more secure approach.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Confusion:&lt;/strong&gt; Deep linking can result in broken or misrouted links that confuse users; OTPs provide clear, straightforward instructions for resetting passwords.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance Overhead:&lt;/strong&gt; Managing deep links involves extra coding and constant updates for compatibility, whereas OTP-based systems integrate smoothly with platforms like Supabase, reducing maintenance effort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability Issues:&lt;/strong&gt; Deep links may fail if the app isn’t installed or misconfigured, but OTPs work independently of the app’s state, ensuring a consistent reset experience for all users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll share my journey of ditching deep linking in favor of a secure, token-based reset flow. I'll walk you through how I customized the email template, triggered the reset email, and built a straightforward UI for users to enter their token and new password.&lt;/p&gt;

&lt;p&gt;Let's dive in and see how this change transformed my approach to handling password resets.&lt;/p&gt;




&lt;h2&gt;
  
  
  Email Template
&lt;/h2&gt;

&lt;p&gt;When users forget their passwords, a smooth and secure reset process is crucial. Supabase made this easier by letting me customize their email templates. I started by heading to &lt;strong&gt;Authentication &amp;gt; Email Templates&lt;/strong&gt; in the Supabase dashboard and editing the "Reset Password" template. I used this simple HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h2&amp;gt;Reset Password&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Follow the instructions below to reset your password:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Enter the token below in the app:&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;{{ .Token }}&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Supabase automatically replaces {{ .Token }} with a unique token.&lt;/p&gt;
&lt;h2&gt;
  
  
  Integrating the Reset Flow in My App
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sending the Reset Email&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I used the Supabase client to trigger the reset email when a user enters their email:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import { supabase } from './supabaseClient';

async function sendResetPasswordEmail(email) {
  const { error } = await supabase.auth.resetPasswordForEmail(email);
  if (error) {
    console.error('Error:', error.message);
  } else {
    console.log('Reset email sent!');
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Building the Reset Form&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, I built a simple React component to let users enter their token and new password:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import React, { useState } from 'react';
import { supabase } from './supabaseClient';

const ResetPasswordForm = () =&amp;gt; {
  const [token, setToken] = useState('');
  const [newPassword, setNewPassword] = useState('');
  const [message, setMessage] = useState('');

  const handleReset = async (e) =&amp;gt; {
    e.preventDefault();
    const { error } = await supabase.auth.api.updateUser(token, { password: newPassword });
    setMessage(error ? `Error: ${error.message}` : 'Password reset successful!');
  };

  return (
    &amp;lt;form onSubmit={handleReset}&amp;gt;
      &amp;lt;label&amp;gt;Reset Token:&amp;lt;/label&amp;gt;
      &amp;lt;input value={token} onChange={(e) =&amp;gt; setToken(e.target.value)} required /&amp;gt;
      &amp;lt;label&amp;gt;New Password:&amp;lt;/label&amp;gt;
      &amp;lt;input type="password" value={newPassword} onChange={(e) =&amp;gt; setNewPassword(e.target.value)} required /&amp;gt;
      &amp;lt;button type="submit"&amp;gt;Reset Password&amp;lt;/button&amp;gt;
      {message &amp;amp;&amp;amp; &amp;lt;p&amp;gt;{message}&amp;lt;/p&amp;gt;}
    &amp;lt;/form&amp;gt;
  );
};

export default ResetPasswordForm;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Note: I used supabase.auth.api.updateUser. Check the latest Supabase docs as APIs can change.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  A Little Extra: Skip the Hassle with DeployJet
&lt;/h2&gt;

&lt;p&gt;Now, if you’re planning to build a mobile app and want to skip the hassle of adding analytics, auth, notifications etc from scratch, check out &lt;a href="https://www.deployjet.dev/" rel="noopener noreferrer"&gt;DeployJet&lt;/a&gt;.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://www.deployjet.dev/" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwim8cgq9c0.ufs.sh%2Ff%2FN4yumor6DfRxqUHqItZAhgmG5KBPLS4TYWODU1vozfErVkcQ" height="130" class="m-0" width="504"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://www.deployjet.dev/" rel="noopener noreferrer" class="c-link"&gt;
          DeployJet - A faster way to build and launch mobile apps
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Accelerate your mobile app development with DeployJet’s Expo template and starter kit. Build feature-rich apps fast with our optimized React Native solutions.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.deployjet.dev%2Ffavicon.ico" width="800" height="400"&gt;
        deployjet.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;It’s a game changer for developers who want to focus on building great apps without getting bogged down in setup.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;By customizing the email template and setting up a straightforward UI, I managed to enhance my app’s security and user experience. If you’re looking to do the same, give these steps a try and tweak them to fit your project.&lt;/p&gt;

&lt;p&gt;Happy coding, and feel free to share your experiences or questions in the comments!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>mobile</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Integrating Analytics in Your Mobile App with Vexo</title>
      <dc:creator>Tanmay Kaushik</dc:creator>
      <pubDate>Tue, 18 Feb 2025 19:22:35 +0000</pubDate>
      <link>https://dev.to/tanmay_kaushik_/integrating-analytics-in-your-mobile-app-with-vexo-1l13</link>
      <guid>https://dev.to/tanmay_kaushik_/integrating-analytics-in-your-mobile-app-with-vexo-1l13</guid>
      <description>&lt;p&gt;Hey everyone, I recently started using Vexo for analytics in my mobile app, and I wanted to share my experience on how I set it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Chose Vexo
&lt;/h2&gt;

&lt;p&gt;I was looking for a mobile analytics tool that was easy to integrate and provided real-time data without a ton of hassle. The platform’s clean dashboard and straightforward SDK really is amazing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;First off, I went to the Vexo homepage and signed up for an account. Once I was in, I grabbed my API key from the dashboard. This key is what connects your app to Vexo, so keep it handy!&lt;/p&gt;

&lt;p&gt;For my React Native app, I installed the Vexo SDK using npm. Here’s the command I ran in my terminal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install vexo-analytics --save&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Initializing Vexo in My App
&lt;/h2&gt;

&lt;p&gt;Next, I updated my App.js to initialize Vexo with my API key. It was super straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { View, Text } from 'react-native';
import vexo from 'vexo-analytics'; 

vexo.init({
  apiKey: 'YOUR_VEXO_API_KEY',
});

export default function App() {
  return (
    &amp;lt;View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}&amp;gt;
      &amp;lt;Text&amp;gt;Hey, welcome to my app with Vexo Analytics!&amp;lt;/Text&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tracking Events
&lt;/h2&gt;

&lt;p&gt;One of the coolest parts is tracking user interactions. Let’s say I want to log when someone presses a button. I just add a function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handleButtonPress = () =&amp;gt; {
  Vexo.trackEvent('ButtonPressed', {
    buttonName: 'SignUp',
    timestamp: new Date().toISOString(),
  });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hook this function up to a button’s onPress event, and bam—every time someone taps, Vexo logs the event. I love how easy it is to customize the event data too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking Out the Dashboard
&lt;/h2&gt;

&lt;p&gt;After I integrated everything, I started checking my Vexo dashboard. It’s awesome to see real-time events, understand how users interact with the app, and spot trends that can help me tweak the UX. It feels like having a pulse on what’s happening in my app 24/7.&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%2Fkiy0xzcskd89do7pptvn.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%2Fkiy0xzcskd89do7pptvn.png" alt="Vexo dashboard" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Little Extra: Skip the Hassle with DeployJet
&lt;/h2&gt;

&lt;p&gt;Now, if you’re planning to build a mobile app and want to skip the hassle of adding analytics, auth, notifications etc from scratch, check out &lt;a href="https://www.deployjet.dev/" rel="noopener noreferrer"&gt;DeployJet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s a game changer for developers who want to focus on building great apps without getting bogged down in setup.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>mobile</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>Building Mobile Apps made simple</title>
      <dc:creator>Tanmay Kaushik</dc:creator>
      <pubDate>Mon, 17 Feb 2025 17:04:05 +0000</pubDate>
      <link>https://dev.to/tanmay_kaushik_/i-think-i-solved-the-mobile-app-boilerplate-problem-4cgh</link>
      <guid>https://dev.to/tanmay_kaushik_/i-think-i-solved-the-mobile-app-boilerplate-problem-4cgh</guid>
      <description>&lt;h2&gt;
  
  
  I Loved Building Mobile Apps, But...
&lt;/h2&gt;

&lt;p&gt;Every project was reinventing the wheel—hundreds of lines of boilerplate, tons of integrations, and endless context switching of authentication, payments, notifications, and analytics. Every new project was the same fight, and I couldn't help but wonder: &lt;strong&gt;Is there a better way?&lt;/strong&gt;  &lt;/p&gt;




&lt;h2&gt;
  
  
  The Struggle
&lt;/h2&gt;

&lt;p&gt;I spent &lt;strong&gt;hours and hours&lt;/strong&gt; messing around with configurations, installing third-party services, and trying to kludge together a sensible development workflow. Even when I did manage to get something working, it was &lt;strong&gt;ugly and hard to support&lt;/strong&gt;. I realized that I was spending more time setting up the infrastructure than building the features I was interested in.  &lt;/p&gt;




&lt;h2&gt;
  
  
  My "Aha!" Moment
&lt;/h2&gt;

&lt;p&gt;It had finally become too much after a very long debugging and frustration-filled night. &lt;strong&gt;I was fed up.&lt;/strong&gt; I set my mind on doing something about it.  &lt;/p&gt;

&lt;p&gt;I started constructing a tool that would capture the most vital aspects of mobile app development and unite them into one process. The concept was simple:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Eliminate the mundane setup procedures&lt;/strong&gt; so that I—and everybody else—could devote more time to what matters most: &lt;strong&gt;building awesomeness.&lt;/strong&gt;  &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Journey
&lt;/h2&gt;

&lt;p&gt;I started by assembling the most frequent pain points:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Auth&lt;/strong&gt;: Social sign-ins, email/password setups, and password reset were always such a hassle.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payments&lt;/strong&gt;: Apple Pay and Google Pay integration required a lot of boilerplate.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notifications &amp;amp; Analytics&lt;/strong&gt;: These services were spread all over various platforms, each with its own learning curve.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Slowly, I began developing a solution that addressed each of these issues. I iterated &lt;strong&gt;on a rapid cycle&lt;/strong&gt;, testing out ideas and refining the tool until it became a seamless part of my development process.  &lt;/p&gt;




&lt;h2&gt;
  
  
  The Outcome
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://www.deployjet.dev/" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwim8cgq9c0.ufs.sh%2Ff%2FN4yumor6DfRxqUHqItZAhgmG5KBPLS4TYWODU1vozfErVkcQ" height="130" class="m-0" width="504"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://www.deployjet.dev/" rel="noopener noreferrer" class="c-link"&gt;
          DeployJet - A faster way to build and launch mobile apps
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Accelerate your mobile app development with DeployJet’s Expo template and starter kit. Build feature-rich apps fast with our optimized React Native solutions.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.deployjet.dev%2Ffavicon.ico" width="800" height="400"&gt;
        deployjet.dev
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Today, I have a solution that bundles all these integrations into &lt;strong&gt;one unified process&lt;/strong&gt;. It's not a silver bullet, but it has &lt;strong&gt;significantly reduced setup time and complexity&lt;/strong&gt; for my projects.  &lt;/p&gt;

&lt;p&gt;More importantly, it has allowed me to get back to what I love—&lt;strong&gt;coding and creating apps that make a difference.&lt;/strong&gt;  &lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This journey wasn’t just about saving time; it was about &lt;strong&gt;reclaiming the joy of development&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;If you’ve ever felt &lt;strong&gt;bogged down by repetitive setup tasks&lt;/strong&gt;, know that you’re not alone. Sometimes, the best way to solve a problem is to &lt;strong&gt;build something yourself&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/J58pxr5v07Q"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks for reading, and happy coding!&lt;/strong&gt; 🚀&lt;/p&gt;

</description>
      <category>ios</category>
      <category>android</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
