0

I'm making an app that makes a search after the artist name using spotify API and I am getting this error: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.

spotify.service.ts

import { Injectable } from '@angular/core';
import { Http, Headers, Response } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class SpotifyService {
  private searchUrl: string;
  
    private client_id ='****************************';
    private client_secret = '*********************************';
    private access_token:string;
    private encoded = btoa(this.client_id + ':' + this.client_secret);

  constructor(private http: Http) { }

  getToken(){
     var params = ('grant_type=client_credentials');

     var headers = new Headers();

     headers.append( 'Authorization', 'Basic ' + this.encoded);
     headers.append('Content-Type' , 'application/x-www-form-urlencoded');

     return this.http.post('https://accounts.spotify.com/api/token', params , {headers : headers} )
     .map(res=> res.json());
  }


  searchMusic(str: string, type='artist', token: string) {
    console.log(this.encoded);
    this.searchUrl = 'https://api.spotify.com/v1/search?query='+str+'&offset=0&limit=20&type='+type;
    let headers = new Headers();
    headers.append('Authorization', 'Bearer' + token);

    return this.http.get(this.searchUrl, {headers: headers})
    .map((res: Response) => res.json())
  }

}

I want to display the results in search.component.html. This is the search.component.ts

import { Component, OnInit } from '@angular/core';
import { SpotifyService } from '../spotify.service';
import { Artist } from '../../../Artist';


@Component({
  selector: 'app-search',
  templateUrl: './search.component.html',
  styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {
  searchStr: string;
  searchRes: Artist[];

  constructor(private spotifyService: SpotifyService) { }

  ngOnInit() {
  }

  searchMusic() {
    this.spotifyService.getToken()
    .subscribe(res => {
      this.spotifyService.searchMusic(this.searchStr, 'artist', res.access_token)
    .subscribe(res => {
      this.searchRes = res.articles.items;
    })
    })
    
  }

}

I've also tried to use this proxyUrl:

getToken(){
     var params = ('grant_type=client_credentials');

     const proxyUrl = "https://cors-anywhere.herokuapp.com/";

     var headers = new Headers();

     
     headers.append( 'Authorization', 'Basic ' + this.encoded);
     headers.append('Content-Type' , 'application/x-www-form-urlencoded');

     return this.http.post(proxyUrl + 'https://accounts.spotify.com/api/token', params , {headers : headers} )
     .map(res=> res.json());
  }

But I'm getting this error now: "Only valid bearer authentication supported".

P.S. I don't want to bypass the CORS or install any extensions!

Ovidiu Ionut
  • 1,452
  • 1
  • 8
  • 14
  • 1
    This is a CORS issue. The server you are making request to is not allowing the origin from where the request is being made. Talk to your API developer to allow the domain from where the request is originated. – Ritesh Waghela Sep 27 '18 at 11:09
  • Possible duplicate of [XmlHttpRequest error: Origin null is not allowed by Access-Control-Allow-Origin](https://stackoverflow.com/questions/3595515/xmlhttprequest-error-origin-null-is-not-allowed-by-access-control-allow-origin) – Lazar Ljubenović Sep 27 '18 at 11:11
  • That API is meant to be consumed on the back end which is why you have a `client_secret`, it's meant to be secret. Adding it to a frontend wouldn't be keeping it secret since everyone can see it – Patrick Evans Sep 27 '18 at 11:11
  • proxy on server side is the solution, check this one out: http://oskarhane.com/avoid-cors-with-nginx-proxy_pass/ – Drahoš Maďar Sep 27 '18 at 11:42

2 Answers2

0

Install this chrome extension and it will let you bypass CORS. I use it frequently when working with APIs in my localhost. Chrome CORS extention

0
https://accounts.spotify.com/api/token

That spotifiy endpoint is supposed to be consumed on the backend. It is why you have a client_secret token. You make a request on the backend using those credentials and get back a token. You then send that token to the frontend.

On the frontend you then use that token for the other endpoints like https://api.spotify.com/v1/ which have the CORS headers setup for allowing cross domain requests.

For instance:

var authToken = null;
fetch('http://yourserver.com/requestNewToken').then(token=>{
  authToken = token;
  //now use that token with your frontend requests like:
  searchMusic(this.searchStr, 'artist', authToken)
});

Where http://yourserver.com/requestNewToken is some endpoint you make on your server where you would make the call to https://accounts.spotify.com/api/token and return the token response.

Side note since your client_secret is now compromised you should get a new one made.

Also make sure to read through Spotify's developers help pages like the Client Credentials Flow and the Authorization page as a whole for better understanding the correct flow patterns for making requests.

Patrick Evans
  • 41,991
  • 6
  • 74
  • 87