Home > OS >  Angular does not display JWT protected pictures but it loads them properly?
Angular does not display JWT protected pictures but it loads them properly?

Time:09-18

I'm writing an Angular application (version 14.1) where I fetch images from my backend which are protected by a JSON web token. Meaning, each time the user wants to fetch an image from the backend, a valid JWT needs to be attached onto the request, otherwise you get back a http403 forbidden. From a browser perspective this seems to work fine, I see a preview of the image that gets loaded by the Angular application in the developer's console of firefox, also the request gets trough fine with http200 for the GET request and also for the OPTIONS requests which triggers in forehand. But the image does not get displayed for some reason even when everything went through fine, why that ?!

To make Angular fetch the image using a JWT I do the following in combination with the JwtModule from '@auth0/angular-jwt':

media.component.ts:

import { Component, OnInit } from '@angular/core';
import {environment} from "../../environments/environment";
import {HttpClient} from "@angular/common/http";
import {firstValueFrom} from "rxjs";


export interface RecentlyAddedMoviesResponse {
  id: string;
  title: string;
  cover_url: string;
  directors: string;
}



@Component({
  selector: 'app-media',
  templateUrl: './media.component.html',
  styleUrls: ['./media.component.css']
})
export class MediaComponent implements OnInit {
  public recently_added_movies: RecentlyAddedMoviesResponse[] = []

  constructor(private http: HttpClient) { }


  async ngOnInit(): Promise<void> {
    const recently_added_movies = await firstValueFrom(this.http.get<[RecentlyAddedMoviesResponse]>(environment.backend   '/api/v1/movies/recently_added'));
    this.recently_added_movies = await Promise.all(recently_added_movies.map(async (movie) => {
      movie.cover_url = URL.createObjectURL(await firstValueFrom(this.http.get(movie.cover_url, {responseType: 'blob'})));
      return movie;
    }));
  }
}

What I do here to attach the JWT to the fetch request of Angular is to basically replace the original image by a blob which I then want to render at my HTML template like so:

<h3 >Recently added Movies</h3>
<div >
  <a *ngFor="let movie of recently_added_movies">
  <div >
    <div >
      <img  src="{{ movie.cover_url }}">
      <div >
        <strong >{{ movie.title | slice:0:20 }}</strong><br>
      </div>
    </div>
  </div>
</a>
</div>

But it makes zero sense to me that the browser does not want to display the image at all, especially because everything gets loaded perfectly. Have I missed something here? This is what I get in return from the request to my backend:

enter image description here

And this is what gets displayed:

enter image description here

Thanks in advance

CodePudding user response:

Your image URLs probably intercepted by the angular DomSanitizer. What you need to do is tell the angular to security bypass your image URLs. Below is how you do so :

@Component({
  selector: 'app-media',
  templateUrl: './media.component.html',
  styleUrls: ['./media.component.css']
})
export class MediaComponent implements OnInit {
  public recently_added_movies: RecentlyAddedMoviesResponse[] = []

  constructor(private http: HttpClient, private sanitizer: DomSanitizer) { }


  async ngOnInit(): Promise<void> {
    const recently_added_movies = await firstValueFrom(this.http.get<[RecentlyAddedMoviesResponse]>(environment.backend   '/api/v1/movies/recently_added'));
    this.recently_added_movies = await Promise.all(recently_added_movies.map(async (movie) => {
     // here you bypass security.
      movie.cover_url = <string>this.sanitizer.bypassSecurityTrustResourceUrl( URL.createObjectURL(await firstValueFrom(this.http.get(movie.cover_url, {responseType: 'blob'}))));
      return movie;
    }));
  }
}

Also, prefer property binding over interpolation when you are passing data to attributes.

  • Related