
Hey Angular developers! 🅰️ It's about that time again for yet another article. In this guide, we're going to dive into how to integrateSupabase, with Angular to build a secure authentication application. We’ll set up signup, and login authentication with Supabase in Angular and protect routes of some pages. Let’s get started
Prerequisites
Before we dive in, make sure you've got:
- An Angular project
- Node.js v16+ installed
- A Supabase account atSupabase Website
Step 1: Set Up a Supabase Project
Create a New Project:
- Log in to Supabase and click New Project.
- Enter a project name, and database password, and choose a region.
- Wait a few minutes for the project to provision.
Retrieve API Credentials:
On the project overview section, Copy theProject URL andanon public (API Key).
Step 2: Create an Angular Project
- Generate a New Angular App:
ng new supabase-auth-app
Choose your preferred styling when prompted.
- Install Dependencies: Install the Supabase JavaScript client:
npminstall @supabase/supabase-js
Step 3: Configure Supabase in Angular
- Set Up Environment Variables: Store the Supabase credentials securely in Angular’s environment files.
Opensrc/environments/environment.ts and add:
exportconst environment={ production:false, supabaseUrl:'SUPABASE_URL', supabaseKey:'SUPABASE_ANON_KEY'};
ReplaceSUPABASE_URL andSUPABASE_ANON_KEY with values from the Supabase dashboard.
- Create Type Definitions: Insrc/app/types/user.type.ts, define types for user data and payloads:
export typeUser={id: string; email?: string; phone?: string; user_metadata:{ displayName?: string;};};export typeSignupPayload={ name: string; email: string; password: string;};export typeLoginPayload={ email: string; password: string;};
- Create a Supabase Service: Generate a service to manage Supabase interactions:
ng generate service services/supabase
Updatesrc/app/services/supabase.service.ts to initialize the Supabase client and handle authentication:
import{ Injectable} from'@angular/core';import{ createClient, SupabaseClient} from'@supabase/supabase-js';import{ environment} from'../../environments/environment';import{ LoginPayload, SignupPayload} from'../types/user.type';@Injectable({ providedIn:'root',})exportclass SupabaseService{ privatereadonlysupabase: SupabaseClient; constructor(){ this.supabase= createClient( environment.supabaseUrl, environment.supabaseKey);} async signInWithEmail(payload: LoginPayload){returnawait this.supabase.auth.signInWithPassword({ email: payload.email, password: payload.password,});} async signUpWithEmail(payload: SignupPayload){returnawait this.supabase.auth.signUp({ email: payload.email, password: payload.password, options:{ data:{ displayName: payload.name,},},});} async getUser(){returnawait this.supabase.auth.getUser();} async signOut(){returnawait this.supabase.auth.signOut();}}
The SupabaseService centralizes authentication logic, making it reusable across components. It handles initialization, user state, and auth methods, ensuring clean and maintainable code.
Step 4: Set Up Authentication Components
- We’ll create components for login, signup, and profile pages.
Generate Components:
ng generate component auth/loginng generate component auth/signup ng generate component profile
- Login Component: Updatesrc/app/auth/login/login.component.ts to handle email/password login:
import{ Component, inject, signal} from'@angular/core';import{ SupabaseService} from'../../services/supabase.service';import{ Router} from'@angular/router';import{ FormsModule} from'@angular/forms';@Component({ selector:'app-login', imports:[FormsModule], templateUrl:'./login.component.html', styleUrl:'./login.component.css',})exportclass LoginComponent{ email= signal(''); password= signal(''); privatereadonlysupabaseService= inject(SupabaseService); privatereadonlyrouter= inject(Router); async signInWithEmail(){ const{ error}= await this.supabaseService.signInWithEmail({ email: this.email(), password: this.password(),});if(error){ alert('Error signing in: ' + error.message);}else{ this.router.navigate(['/profile']);}} navigateToSignup(){ this.router.navigate(['/signup']);}}
- Updatesrc/app/auth/login/login.component.html:
<divclass="container"> <h2>Login</h2> <form> <inputtype="email"[(ngModel)]="email"name="email"placeholder="Email" required /> <inputtype="password"[(ngModel)]="password"name="password"placeholder="Password" required /> <buttontype="button"(click)="signInWithEmail()">Sign In</button> </form> <p>Don't have an account? <a (click)="navigateToSignup()">Sign Up</a></p></div>
- Add styling(optional), insrc/app/auth/login/login.component.css:
.container{ max-width: 400px; margin: 50px auto; padding: 20px; border: 1px solid#ccc; border-radius: 5px;}input, button{ display: block; width: 100%; margin: 10px 0; padding: 10px;}button{ background-color:#007bff; color: white; border: none; cursor: pointer;}button:hover{ background-color:#0056b3;}
- Signup Component: Updatesrc/app/auth/signup/signup.component.ts:
import{ Component, inject, signal} from'@angular/core';import{ FormsModule} from'@angular/forms';import{ SupabaseService} from'../../services/supabase.service';import{ Router} from'@angular/router';@Component({ selector:'app-signup', imports:[FormsModule], templateUrl:'./signup.component.html', styleUrl:'./signup.component.css',})exportclass SignupComponent{ name= signal(''); email= signal(''); password= signal(''); privatereadonlysupabaseService= inject(SupabaseService); privatereadonlyrouter= inject(Router); async signUp(){ const{ error}= await this.supabaseService.signUpWithEmail({ name: this.name(), email: this.email(), password: this.password(),});if(error){ alert('Error signing up: ' + error.message);}else{ alert('Check your email to confirm your account!'); this.router.navigate(['/login']);}} navigateToLogin(){ this.router.navigate(['/login']);}}
- Updatesrc/app/auth/signup/signup.component.html:
<divclass="container"> <h2>Sign Up</h2> <form> <inputtype="text"[(ngModel)]="name"name="name"placeholder="Full Name" required /> <inputtype="email"[(ngModel)]="email"name="email"placeholder="Email" required /> <inputtype="password"[(ngModel)]="password"name="password"placeholder="Password" required /> <buttontype="button"(click)="signUp()">Sign Up</button> </form> <p>Already have an account? <a(click)="navigateToLogin()">Log In</a></p></div>
Use the same CSS as the login component(signup.component.css).
- Profile Component: Updatesrc/app/profile/profile.component.ts:
import{ Component, inject, OnInit} from'@angular/core';import{ SupabaseService} from'../services/supabase.service';import{ Router} from'@angular/router';import{ User} from'../types/user.type';@Component({ selector:'app-profile', imports:[], templateUrl:'./profile.component.html', styleUrl:'./profile.component.css',})exportclass ProfileComponent implements OnInit{ user: User | null= null; privatereadonlysupabaseService= inject(SupabaseService); privatereadonlyrouter= inject(Router); ngOnInit(){ this.fetchUser();} async fetchUser(){ const{ data}= await this.supabaseService.getUser(); this.user= data.user;if(!this.user){ this.router.navigate(['/login']);}} async signOut(){ await this.supabaseService.signOut(); this.router.navigate(['/login']);}}
- Update
src/app/profile/profile.component.html
:
<divclass="container"> <h2>User Profile</h2> <p> Congratulations! Welcome to secure auth with Angular + Supabase is running. 🎉 </p> @if(user){ <p>User ID:{{ user.id}}</p> <p>Email:{{ user.email}}</p> <p>Display Name:{{ user.user_metadata.displayName}}</p>} <button(click)="signOut()">Sign Out</button></div>
Step 5: Configure Routing and Route Protection
- Create an Auth Guard: Generate a guard:
ng generate guard guards/auth
- Updatesrc/app/guards/auth.guard.ts:
import{ inject} from'@angular/core';import{ CanActivateFn, Router} from'@angular/router';import{ SupabaseService} from'../services/supabase.service';exportconst authGuard: CanActivateFn= async(route, state)=>{ const supabaseService= inject(SupabaseService); const router= inject(Router); const user= await supabaseService.getUser();if(!user){ router.navigate(['/login'],{ queryParams:{ returnUrl: state.url}});returnfalse;}returntrue;};
- Set Up Routes: Updatesrc/app/app.routes.ts to use lazy loading and protect the profile route:
import{ Routes} from'@angular/router';import{ authGuard} from'./guards/auth.guard';exportconst routes: Routes=[{ path:'', redirectTo:'/login', pathMatch:'full'},{ path:'login', loadComponent:()=> import('./auth/login/login.component').then((c)=> c.LoginComponent),},{ path:'signup', loadComponent:()=> import('./auth/signup/signup.component').then((c)=> c.SignupComponent),},{ path:'profile', loadComponent:()=> import('./profile/profile.component').then((c)=> c.ProfileComponent), canActivate:[authGuard],},];
Run Application
Using the command:
ng serve -o
This will run and open the application in the default browser.
After successful sign-in🎉🎉🎉
Conclusion
We’ve just built a secure authentication system in Angular using Supabase, complete with email/password signup, login, and route protection.
This setup is a solid foundation for more advanced features like role-based access, password resets, or social logins, all supported by Supabase.
Access the full source code onGitHub.
For more customization and ideas, explore theSupabase Docs.
Happy coding! 🅰️⚡
Top comments(5)

- EducationDidn't finish high school :(
- PronounsNev/Nevo
- WorkOSS Chief @ Gitroom
- Joined
Pretty cool seeing a real breakdown like this - makes me wanna roll up my sleeves and build something tonight.

- Email
- LocationRemote
- EducationUniversity Of Education
- PronounsHe/Him/His
- WorkSoftware Engineer
- Joined
@nevodavid roll up your sleeves and let me see what you're cooking tonight

- Email
- LocationAccra, Ghana
- EducationTakoradi Technical University
- Joined
This is interesting work done Kingsley, I have been looking for this for awhile now, thanks for writting this article, I know it will help me.

- Email
- LocationRemote
- EducationUniversity Of Education
- PronounsHe/Him/His
- WorkSoftware Engineer
- Joined
You're welcome George
Some comments may only be visible to logged-in visitors.Sign in to view all comments.
For further actions, you may consider blocking this person and/orreporting abuse