Introduction is a development platform for building WEB, mobile and desktop applications using HTML, CSS and TypeScript (JavaScript). Currently, Angular is at version 14 and Google is the main maintainer of the project. Angular is an authentication service with simple tools to help developers build applications. Supabase Prerequisites Before you start, you need to install and configure the tools: git Node.js and npm Angular CLI IDE (e.g. ) Visual Studio Code Getting started Create and configure the account on the Supabase Let's create the account. Access the site and click on the button . 1. https://supabase.io/ Start your project Click on the button . 2. Continue with GitHub Fill in the fields , and click on the button to login with your GitHub account and if you don't have an account, click on the button to create a new account. there is a step-by-step guide to creating a GitHub account. 3. Username or email address Password Sign in Create an account In this tutorial Click on the button . 4. Authorize supabase Click on the button . 5. New project Click on the menu with the organization name created automatically. 6. Select an , fill in the fields and , select a and click on the button . 7. Organization Name Database Password Region Create new project Wait for the project creation. 8. Click on the button to copy the key that has been generated, in my case, the key was copied. Click on the button to copy the URL that has been generated, in my case, the URL was copied because this key and URL will be configured in the Angular application. 9. Copy eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYzNTA4NjA1MCwiZXhwIjoxOTUwNjYyMDUwfQ.CzFuYS6XKvEwW5OsAAPAcHvuo-NVE4PUwDSKgqK9Yas Copy https://wzlpmcsxrxogtctlznel.supabase.co Click on the menu to setting up the database schema. 10. SQL Click on the card . 11. User Management Starter Click on the button . 12. RUN Ready! Account created, key generated and database schema configured. 13. Create the Angular application Let's create the application with the Angular base structure using the with the route file and the SCSS style format. 1. @angular/cli ng new angular-supabase --routing true --style scss CREATE angular-supabase/README.md (1062 bytes) CREATE angular-supabase/.editorconfig (274 bytes) CREATE angular-supabase/.gitignore (604 bytes) CREATE angular-supabase/angular.json (3267 bytes) CREATE angular-supabase/package.json (1080 bytes) CREATE angular-supabase/tsconfig.json (783 bytes) CREATE angular-supabase/.browserslistrc (703 bytes) CREATE angular-supabase/karma.conf.js (1433 bytes) CREATE angular-supabase/tsconfig.app.json (287 bytes) CREATE angular-supabase/tsconfig.spec.json (333 bytes) CREATE angular-supabase/src/favicon.ico (948 bytes) CREATE angular-supabase/src/index.html (301 bytes) CREATE angular-supabase/src/main.ts (372 bytes) CREATE angular-supabase/src/polyfills.ts (2820 bytes) CREATE angular-supabase/src/styles.scss (80 bytes) CREATE angular-supabase/src/test.ts (788 bytes) CREATE angular-supabase/src/assets/.gitkeep (0 bytes) CREATE angular-supabase/src/environments/environment.prod.ts (51 bytes) CREATE angular-supabase/src/environments/environment.ts (658 bytes) CREATE angular-supabase/src/app/app-routing.module.ts (245 bytes) CREATE angular-supabase/src/app/app.module.ts (393 bytes) CREATE angular-supabase/src/app/app.component.scss (0 bytes) CREATE angular-supabase/src/app/app.component.html (24617 bytes) CREATE angular-supabase/src/app/app.component.spec.ts (1103 bytes) CREATE angular-supabase/src/app/app.component.ts (221 bytes) ✔ Packages installed successfully. Successfully initialized git. Install and configure the Bootstrap CSS framework. Do steps 2 and 3 of the post . 2. Adding the Bootstrap CSS framework to an Angular application Configure the variable with the Supabase URL and the variable with the Supabase key in the and files as below. 3. supabase.url supabase.key src/environments/environment.ts src/environments/environment.prod.ts supabase: { url: 'https://wzlpmcsxrxogtctlznel.supabase.co', key: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYzNTA4NjA1MCwiZXhwIjoxOTUwNjYyMDUwfQ.CzFuYS6XKvEwW5OsAAPAcHvuo-NVE4PUwDSKgqK9Yas', }, Install the library. 4. @supabase/supabase-js npm install @supabase/supabase-js Create the service. 5. SupabaseService ng generate service supabase --skip-tests=true CREATE src/app/supabase.service.ts (137 bytes) Change the file and add the lines as below. 6. supabase.service.ts import { Injectable } from '@angular/core'; import { AuthChangeEvent, createClient, Session, SupabaseClient, User } from '@supabase/supabase-js'; import { environment } from '../environments/environment'; export interface IUser { email: string; name: string; website: string; url: string; } @Injectable({ providedIn: 'root', }) export class SupabaseService { private supabaseClient: SupabaseClient; constructor() { this.supabaseClient = createClient(environment.supabase.url, environment.supabase.key); } public getUser(): User|null { return this.supabaseClient.auth.user(); } public getSession(): Session|null { return this.supabaseClient.auth.session(); } public getProfile(): PromiseLike<any> { const user = this.getUser(); return this.supabaseClient.from('profiles') .select('username, website, avatar_url') .eq('id', user?.id) .single(); } public authChanges(callback: (event: AuthChangeEvent, session: Session | null) => void): any { return this.supabaseClient.auth.onAuthStateChange(callback); } public signIn(email: string): Promise<any> { return this.supabaseClient.auth.signIn({ email, }); } public signOut(): Promise<any> { return this.supabaseClient.auth.signOut(); } public updateProfile(userUpdate: IUser): any { const user = this.getUser(); const update = { username: userUpdate.name, website: userUpdate.website, id: user?.id, updated_at: new Date(), }; return this.supabaseClient.from('profiles').upsert(update, { returning: 'minimal', // Do not return the value after inserting }); } } Create the component. 7. SignInComponent ng generate component sign-in --skip-tests=true CREATE src/app/sign-in/sign-in.component.scss (0 bytes) CREATE src/app/sign-in/sign-in.component.html (22 bytes) CREATE src/app/sign-in/sign-in.component.ts (279 bytes) UPDATE src/app/app.module.ts (493 bytes) Change the file. Import the and services and create the method as below. 8. src/app/sign-in/sign-in.component.ts Router SupabaseService signIn import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { IUser, SupabaseService } from '../supabase.service'; @Component({ selector: 'app-sign-in', templateUrl: './sign-in.component.html', styleUrls: ['./sign-in.component.scss'], }) export class SignInComponent { loading: boolean; user: IUser; constructor(private router: Router, private supabaseService: SupabaseService) { this.loading = false; this.user = {} as IUser; } public signIn(): void { this.loading = true; this.supabaseService.signIn(this.user.email) .then(() => { }).catch(() => { this.loading = false; }); } } Change the file. Add the lines as below. 9. src/app/sign-in/sign-in.component.html <div class="row justify-content-center my-5"> <div class="col-4"> <div class="card"> <div class="card-body"> <div class="row"> <div class="col mb-2"> <label for="email" class="form-label">Email:</label> <input type="email" id="email" name="email" #email="ngModel" [(ngModel)]="user.email" class="form-control form-control-sm"> </div> </div> <div class="row"> <div class="col d-grid"> <button type="button" (click)="signIn()" class="btn btn-sm btn-success" [disabled]="loading"> <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" *ngIf="loading"></span> Sign in </button> </div> </div> </div> </div> </div> </div> Create the component. 10. ProfileComponent ng generate component profile --skip-tests=true CREATE src/app/profile/profile.component.scss (0 bytes) CREATE src/app/profile/profile.component.html (22 bytes) CREATE src/app/profile/profile.component.ts (280 bytes) UPDATE src/app/app.module.ts (642 bytes) Change the file. Import the service and create the method as below. 11. src/app/profile/profile.component.ts SupabaseService update import { Component, OnInit } from '@angular/core'; import { IUser, SupabaseService } from '../supabase.service'; @Component({ selector: 'app-profile', templateUrl: './profile.component.html', styleUrls: ['./profile.component.scss'], }) export class ProfileComponent implements OnInit { loading: boolean; user: IUser; constructor(private supabaseService: SupabaseService) { this.loading = false; this.user = {} as IUser; } public ngOnInit(): void { const session = this.supabaseService.getSession(); if (session && session.user && session.user.email) { this.user.email = session.user.email; } this.supabaseService.getProfile() .then((success: any) => { if (success && success.profile) { this.user.name = success.profile.username; this.user.website = success.profile.website; this.user.url = success.profile.avatar_url; } }); } public update(): void { this.loading = true; this.supabaseService.updateProfile(this.user) .then(() => { this.loading = false; }).catch(() => { this.loading = false; }); } } Change the file and add the lines as below. 12. src/app/profile/profile.component.html <div class="row justify-content-center my-5"> <div class="col-4"> <div class="row" *ngIf="user.url"> <div class="col mb-2 text-center"> <img [src]="user.url" class="rounded-circle"> </div> </div> <div class="row"> <div class="col mb-2"> <label for="email" class="form-label">Email:</label> <input type="email" id="email" name="email" #email="ngModel" [(ngModel)]="user.email" disabled class="form-control form-control-sm"> </div> </div> <div class="row"> <div class="col mb-2"> <label for="name" class="form-label">Name:</label> <input type="text" id="name" name="name" #name="ngModel" [(ngModel)]="user.name" class="form-control form-control-sm"> </div> </div> <div class="row"> <div class="col mb-2"> <label for="website" class="form-label">Website:</label> <input type="text" id="website" name="website" #website="ngModel" [(ngModel)]="user.website" class="form-control form-control-sm"> </div> </div> <div class="row"> <div class="col d-grid"> <button type="button" (click)="update()" class="btn btn-sm btn-dark" [disabled]="loading"> <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" *ngIf="loading"></span> Save </button> </div> </div> </div> </div> Change the file. Import the and services and create the and methods as below. 13. src/app/app.component.ts Router SupabaseService isAuthenticated signOut import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { SupabaseService } from './supabase.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], }) export class AppComponent implements OnInit { session: any; constructor(private router: Router, private supabaseService: SupabaseService) { this.session = this.supabaseService.getSession(); } public ngOnInit(): void { this.supabaseService.authChanges((_, session) => this.session = session); } public isAuthenticated(): boolean { if (this.session) { return true; } return false; } public signOut(): void { this.supabaseService.signOut() .then(() => { this.router.navigate(['/signIn']); }); } } Change the file and add the menu as below. 14. src/app/app.component.html <nav class="navbar navbar-expand-sm navbar-light bg-light"> <div class="container-fluid"> <a class="navbar-brand" href="#">Angular Supabase</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div id="navbarContent" class="collapse navbar-collapse"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"> <a class="nav-link" routerLink="/signIn" routerLinkActive="active" *ngIf="!isAuthenticated()">Sign in</a> </li> <li class="nav-item"> <a class="nav-link" routerLink="/profile" routerLinkActive="active" *ngIf="isAuthenticated()">Profile</a> </li> <li class="nav-item"> <a class="nav-link" routerLink="" (click)="signOut()" *ngIf="isAuthenticated()">Sign out</a> </li> </ul> </div> </div> </nav> <router-outlet></router-outlet> Change the file and add the routes as below. 15. src/app/app-routing.module.ts import { ProfileComponent } from './profile/profile.component'; import { SignInComponent } from './sign-in/sign-in.component'; const routes: Routes = [ { path: '', redirectTo: 'signIn', pathMatch: 'full', }, { path: 'profile', component: ProfileComponent, }, { path: 'signIn', component: SignInComponent, }, { path: '**', redirectTo: 'signIn', }, ]; Change the file. Import the module and the and components as below. 16. src/app/app.module.ts FormsModule ProfileComponent SignInComponent import { FormsModule } from '@angular/forms'; import { ProfileComponent } from './profile/profile.component'; import { SignInComponent } from './sign-in/sign-in.component'; declarations: [ AppComponent, ProfileComponent, SignInComponent, ], imports: [ BrowserModule, FormsModule, AppRoutingModule, ], Run the application with the command below. 17. npm start > angular-supabase@1.0.0 start > ng serve ✔ Browser application bundle generation complete. Initial Chunk Files | Names | Size vendor.js | vendor | 2.90 MB styles.css | styles | 268.30 kB polyfills.js | polyfills | 128.51 kB scripts.js | scripts | 76.33 kB main.js | main | 34.20 kB runtime.js | runtime | 6.63 kB | Initial Total | 3.40 MB Build at: 2021-10-25T02:19:20.036Z - Hash: 2dc1cd0da7856970b0d8 - Time: 17203ms Warning: /home/rodrigo/Development/Angular/angular-supabase/node_modules/@supabase/realtime-js/dist/module/RealtimeClient.js depends on 'websocket'. CommonJS or AMD dependencies can cause optimization bailouts. For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ ** ✔ Compiled successfully. Ready! Access the URL and check if the application is working. See the application working on and . 18. http://localhost:4200/ GitHub Pages Stackblitz Testing the application sign in Let's test the application sign in. Access the URL , fill in the field and click on the button . 1. http://localhost:4200/ Email Sign in Open the email with the subject and click on the link . 2. Confirm Your Signup Confirm your mail At this point, you are already signed in. Click on the menu . 3. Profile Fill in the fields and and click on the button . 4. Name Website Update Go back to the Supabase site and click on the menu . 5. New query Fill in the text field with content and click on the button . 6. SELECT * FROM profiles; RUN Check the updated fields and . 7. username website Ready! We test the application sign in and profile update. Supabase documentation is available at . 8. https://supabase.io/docs The application repository is available at . https://github.com/rodrigokamada/angular-supabase This tutorial was posted on my in Portuguese. blog