Home  >  Article  >  Web Front-end  >  Integrate Fingerprint and Face ID Authentication in Your Angular App Using WebAuthn: A Step-by-Step Guide

Integrate Fingerprint and Face ID Authentication in Your Angular App Using WebAuthn: A Step-by-Step Guide

王林
王林Original
2024-09-05 19:00:21821browse

Let’s be honest—we’ve all wished we could log into websites using our fingerprints or Face ID, just like on mobile apps, right? Well, thanks to web biometrics, that dream isn’t so far-fetched anymore. Imagine ditching those long, complicated passwords and simply using our fingerprint or face to sign in to our favorite websites. Sounds cool, doesn’t it?

Integrate Fingerprint and Face ID Authentication in Your Angular App Using WebAuthn: A Step-by-Step Guide

Web biometrics, powered by WebAuthn, is making this possible. It's a fancy name for something quite simple: authenticating us with the same kind of security as our phone’s fingerprint sensor or facial recognition, but directly in our web browser. No more worrying about passwords getting leaked or stolen—just a quick scan, and we’re in.

In this tutorial, we’re going to get hands-on with integrating fingerprint and Face ID login into our Angular apps. We’ll cover the essentials, like how the WebAuthn API works and what we need to do on the backend to keep everything secure and smooth. It’s easier than you might think, and by the end, we’ll have our app all set up for the future of authentication. So, let’s dive in and make logging in a breeze!

Understanding WebAuthn: The Basics for Fingerprints and Face-recognition in Angular Apps

Integrate Fingerprint and Face ID Authentication in Your Angular App Using WebAuthn: A Step-by-Step Guide

Alright, before we jump into the code, let’s get a quick handle on what WebAuthn is all about. Think of WebAuthn as the bridge that connects our apps to the cool biometric features we love on our phones—like fingerprints and Face ID—right in our browsers. It uses public key cryptography to authenticate users, which means no more storing plain old passwords that hackers can easily snatch up. Instead, we’re talking about securely generated keys that make our logins both safe and seamless.

Key Objects and Their Roles

To get things rolling, we need to understand a couple of key players in the WebAuthn game: PublicKeyCredentialCreationOptions and PublicKeyCredentialRequestOptions. Don’t let the long names scare you—they’re just fancy ways to tell the browser how we want to register and authenticate users.

1. PublicKeyCredentialCreationOptions

This is our go-to object when setting up new user credentials. It includes:

  • challenge: A unique, random value generated by the server to ensure the response is fresh and can’t be reused.
  • rp: Stands for Relying Party (our app) and includes details like the app’s name and ID.
  • user: Info about the user, like a unique ID, username, and display name.
  • pubKeyCredParams: A list of public key algorithms we’ll allow.
  • authenticatorSelection: Helps us choose the right type of authenticator based on things like attachment type (platform or cross-platform) and user verification level.

2. PublicKeyCredentialRequestOptions

When it’s time to verify our users, this object takes the spotlight. It includes:

  • challenge: Just like before, this ensures our authentication request is fresh and unique.
  • allowCredentials: Specifies which credentials are allowed for the user.
  • userVerification: Dictates whether user verification (like a fingerprint scan) is required.

With these objects in hand, our Angular app will be able to guide users through registering their biometric data and authenticating quickly and securely. Next, we’ll get into the code and see how to make this magic happen in our app!

Setting Up the Angular App

In this section, we’ll guide you through setting up an Angular application with biometric authentication using WebAuthn. We’ll focus on using fingerprints and Face ID, so let's get our hands dirty!

Step 1: Setting Up Our Angular Project

To get started, let’s create a new Angular project. Open your terminal and type the following commands:

ng new web-biometrics-demo
cd web-biometrics-demo
ng serve

This sets up a basic Angular application, and running ng serve will start your app on http://localhost:4200/. You should see the default Angular welcome page. Now, we’re ready to integrate WebAuthn for biometric authentication.

Step 2: Creating the WebAuthn Service

We need a service in Angular to manage all our WebAuthn functionality, including registration and authentication using biometrics. Let’s create this service by running:

ng generate service services/webauthn

Now, open webauthn.service.ts and add the following code:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class WebAuthnService {

  constructor() { }

  // Generates a random buffer to use as a challenge, which is a unique value needed for security
  private generateRandomBuffer(length: number): Uint8Array {
    const randomBuffer = new Uint8Array(length);
    window.crypto.getRandomValues(randomBuffer); // Fills the buffer with cryptographically secure random values
    return randomBuffer;
  }

  // Registers a new credential (like a fingerprint or Face ID) for the user
  async register() {
    // Generate a unique challenge for the registration process
    const challenge = this.generateRandomBuffer(32);

    // PublicKeyCredentialCreationOptions is the core object needed for registration
    const publicKey: PublicKeyCredentialCreationOptions = {
      challenge: challenge, // A random value generated by the server to ensure the request is fresh and unique
      rp: { // Relying Party (your app) information
        name: "OurAwesomeApp" // Display name of your app
      },
      user: { // User information
        id: this.generateRandomBuffer(16), // A unique identifier for the user
        name: "user@example.com", // User's email or username
        displayName: "User Example" // A friendly name for the user
      },
      pubKeyCredParams: [{ // Array of acceptable public key algorithms
        type: "public-key",
        alg: -7  // Represents the ES256 algorithm (Elliptic Curve Digital Signature Algorithm)
      }],
      authenticatorSelection: { // Criteria for selecting the appropriate authenticator
        authenticatorAttachment: "platform", // Ensures we use the device's built-in biometric authenticator like Touch ID or Face ID
        userVerification: "required" // Requires user verification (e.g., fingerprint or face scan)
      },
      timeout: 60000, // Timeout for the registration operation in milliseconds
      attestation: "direct" // Attestation provides proof of the authenticator's properties and is sent back to the server
    };

    try {
      // This will prompt the user to register their biometric credential
      const credential = await navigator.credentials.create({ publicKey }) as PublicKeyCredential;
      this.storeCredential(credential, challenge); // Store the credential details locally for demo purposes
      console.log("Registration successful!", credential);
      return credential; // Return the credential object containing the user's public key and other details
    } catch (err) {
      console.error("Registration failed:", err);
      throw err; // Handle any errors that occur during registration
    }
  }

  // Authenticates the user with stored credentials (like a fingerprint or Face ID)
  async authenticate() {
    const storedCredential = this.getStoredCredential(); // Retrieve stored credential information
    if (!storedCredential) {
      throw new Error("No stored credential found. Please register first."); // Error if no credentials are found
    }

    // PublicKeyCredentialRequestOptions is used to prompt the user to authenticate
    const publicKey: PublicKeyCredentialRequestOptions = {
      challenge: new Uint8Array(storedCredential.challenge), // A new challenge to ensure the request is fresh and unique
      allowCredentials: [{ // Specifies which credentials can be used for authentication
        id: new Uint8Array(storedCredential.rawId), // The ID of the credential to use
        type: "public-key"
      }],
      userVerification: "required", // Requires user verification (e.g., fingerprint or face scan)
      timeout: 60000 // Timeout for the authentication operation in milliseconds
    };

    try {
      // This will prompt the user to authenticate using their registered biometric credential
      const credential = await navigator.credentials.get({ publicKey }) as PublicKeyCredential;
      console.log("Authentication successful!", credential);
      return credential; // Return the credential object with authentication details
    } catch (err) {
      console.error("Authentication failed:", err);
      throw err; // Handle any errors that occur during authentication
    }
  }

  // Stores credential data in localStorage (for demo purposes only; this should be handled securely in production)
  private storeCredential(credential: PublicKeyCredential, challenge: Uint8Array) {
    const credentialData = {
      rawId: Array.from(new Uint8Array(credential.rawId)), // Converts the raw ID to an array for storage
      challenge: Array.from(challenge) // Converts the challenge to an array for storage
    };
    localStorage.setItem('webauthn_credential', JSON.stringify(credentialData)); // Store the data as a JSON string
  }

  // Retrieves stored credential data from localStorage
  private getStoredCredential(): any {
    const storedCredential = localStorage.getItem('webauthn_credential');
    return storedCredential ? JSON.parse(storedCredential) : null; // Parse the stored JSON back into an object
  }
}

What’s Happening in the Code?

  • generateRandomBuffer: Creates a random buffer that serves as a challenge to ensure each authentication or registration request is unique.

  • register: This method sets up the biometric registration process. It uses PublicKeyCredentialCreationOptions to define parameters like the challenge, relying party (your app), user information, and acceptable public key algorithms. When navigator.credentials.create() is called, the browser prompts the user to register their biometric data.

  • authenticate: This method handles user authentication with biometrics. It uses PublicKeyCredentialRequestOptions to define the authentication challenge and credentials that can be used. The method prompts the user to authenticate with their registered biometrics.

  • storeCredential and getStoredCredential: These methods handle storing and retrieving credentials in localStorage for demonstration purposes.

    In a real-world app, you’d securely store this information on your backend.

Step 3: Building the UI

Now, let’s create a basic UI with buttons to trigger the registration and login functions. This UI will provide feedback based on whether the registration or login was successful.

Open app.component.ts and replace the content with the following:

import { Component } from '@angular/core';
import { WebAuthnService } from './services/webauthn.service';

@Component({
  selector: 'app-root',
  template: `
    <div class="auth-container">
      <h1>Web Biometrics in Angular</h1>
      <button (click)="register()">Register with Fingerprint</button>
      <button (click)="login()">Login with Face ID</button>
      <p *ngIf="message" [ngClass]="{'success': isSuccess, 'error': !isSuccess}">{{ message }}</p>
    </div>
  `,
  styles: [`
    .auth-container {
      text-align: center;
      padding: 50px;
    }
    .success {
      color: green;
    }
    .error {
      color: red;
    }
    button {
      margin: 10px;
      padding: 10px 20px;
      font-size: 16px;
    }
    p {
      margin: 10px;
      font-size: 16px;
    }
  `]
})
export class AppComponent {
  message: string | null = null; // Message to display feedback to the user
  isSuccess: boolean = false; // Indicates if the last action was successful

  constructor(private webAuthnService: WebAuthnService) { }

  // Trigger registration process and update the UI based on the outcome
  async register() {
    try {
      await this.webAuthnService.register();
      this.message = "Registration successful!"; // Success message if registration works
      this.isSuccess = true;
    } catch (err) {
      this.message = "Registration failed. Please try again."; // Error message if something goes wrong
      this.isSuccess = false;
    }
  }

  // Trigger authentication process and update the UI based on the outcome
  async login() {
    try {
      await this.webAuthnService.authenticate();
      this.message = "Authentication successful!"; // Success message if authentication works
      this.isSuccess = true;
    } catch (err) {
      this.message = "Authentication failed. Please try again."; // Error message if something goes wrong
      this.isSuccess = false;
    }
  }
}

What’s Happening in the Component?

register and login methods: These methods call the respective register and authenticate methods from the WebAuthnService. If successful, a success message is displayed; otherwise, an error message is shown.

Template and Styling: The template includes buttons to trigger registration and login, and it displays messages to the user based on the operation's outcome. The buttons are styled for simplicity.

That’s it! We’ve built a basic Angular app with WebAuthn-based biometric authentication, supporting fingerprints and Face ID. This setup captures the core concepts and lays a foundation that can be expanded with additional features and security measures for a production environment.

Backend Considerations

When implementing biometric authentication like fingerprints or Face ID in web applications using WebAuthn, the backend plays a crucial role in managing the security and flow of data. Here’s a breakdown of how the backend processes work in theory, focusing on registration and login functionalities.

Registration: Sign-up

1. User Registration Flow:

  • User Data Capture: During registration, the user provides basic credentials, such as an email and password. If biometric data is also being registered, this is captured as part of the WebAuthn response.

  • Password Hashing: For security, passwords are never stored in plain text. Instead, they are hashed using a library like bcrypt before being stored in the database.

  • Storing WebAuthn Credentials:

    • Challenge Handling: The server sends a challenge during the registration process, which is a randomly generated value to prevent replay attacks.
    • Response Validation: When the client responds with the WebAuthn data, it includes clientDataJSON and attestationObject that need to be decoded and verified.
    • Credential Storage: After validation, key data from the response—like the webauthnId (a unique identifier for the credential) and the publicKey (used to verify future authentications)—are stored in the database alongside the user record.

2. Backend Code Responsibilities:

  • The backend uses libraries like cbor to decode binary data formats from the WebAuthn response, extracting necessary elements like the public key and authenticator data.

  • It ensures that the challenge from the initial registration request matches what is returned in the WebAuthn response to verify the authenticity of the registration.

  • If the WebAuthn response passes all checks, the credentials are saved in the database, linked to the user account.

Login

1. User Login Flow:

  • Challenge Generation: Similar to registration, the server generates a challenge that must be responded to by the client’s authenticator during login.

  • Validating the WebAuthn Response:

    • クライアントは、チャレンジに対する応答を含む PublicKeyCredentialRequestOptions オブジェクトを送り返します。
    • バックエンドはこの応答をデコードして検証し、チャレンジと資格情報がデータベースに保存されているものと一致することを確認します。
  • 資格証明:

    • 登録時に保存された公開キーは、ログイン応答の署名を検証するために使用されます。
    • 資格情報が一致すると、バックエンドはログインを許可し、セッションの認証トークン (JWT など) を生成します。

エラー処理:

  • 不一致または無効な応答: チャレンジ応答が期待値と一致しない場合、または WebAuthn 資格情報が正しく検証されない場合、バックエンドはエラーで応答し、不正アクセスを防ぎます。

  • パスワードへのフォールバック: WebAuthn が失敗するか利用できない場合、システムは従来のパスワード検証に戻すことができ、ユーザーは引き続きアカウントにアクセスできるようになります。

セキュリティに関する考慮事項

  • データの整合性: WebAuthn 認証情報の整合性は重要です。ストレージまたは送信に変更が加えられると検証が失敗するため、認証プロセスが安全になります。

  • チャレンジ ノンス: 独自の時間制限付きチャレンジを使用することで、応答が再利用できないようになり、リプレイ攻撃から保護されます。

  • 公開キーのストレージ: 公開キー (ユーザーになりすますために使用することはできません) のみを保存すると、秘密キーがクライアント デバイスに残るため、セキュリティが強化されます。

これらの原則に従うことで、バックエンドは生体認証を効果的に管理し、Angular アプリで指紋や Face ID などの機能を使用したいユーザーに安全でシームレスなエクスペリエンスを保証します。

要約すれば

このチュートリアルでは、WebAuthn を使用して生体認証を Angular と統合する方法について説明しました。 PublicKeyCredentialCreationOptions や PublicKeyCredentialRequestOptions などの主要な WebAuthn オブジェクトの理解から、登録とログインのプロセスをスムーズにするための Angular サービスと UI コンポーネントの設定まで、基本事項を説明しました。また、生体認証を安全に処理するために必要なバックエンドの考慮事項についても説明しました。

WebAuthn の動作を確認したい方のために、完全な実装を備えたデモとリポジトリを提供しました。ここでデモをチェックアウトしたり、GitHub のこのリポジトリでソース コードを探索したりできます。

生体認証の導入はセキュリティを強化するだけでなく、ユーザーエクスペリエンスを簡素化し、指紋スキャンや素早い顔認識と同じくらい簡単にログインできる未来への道を切り開きます。これらの機能を Angular アプリに統合すると、より安全でユーザー フレンドリーな Web に貢献することになります。コーディングを楽しんでください!

The above is the detailed content of Integrate Fingerprint and Face ID Authentication in Your Angular App Using WebAuthn: A Step-by-Step Guide. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:FunctionsNext article:Functions