Source: lib/auth.js

var base64 = require('base-64')
var defaults = require('./defaults')
var http = require('./http')

/**
 * Create a Spotify authenticator.
 * @constructor
 * @param {string} [clientId] - Client ID.
 * @param {string} [clientSecret] - Client secret key.
 * @param {string} [token] - Access token (if already authenticated).
 */
function SpotifyAuthenticator (clientId, clientSecret, token) {
  /**
   * Client ID.
   */
  this.clientId = clientId || defaults.id

  /**
   * Client secret key.
   */
  this.clientSecret = clientSecret || defaults.key

  /**
   * Access token.
   */
  this.token = token || ''
}

/**
 * Authenticate with the Clients Credentials Flow.
 *
 * Note: this authentication method only works if the script is run
 * from the command line. It does not work when run from a browser,
 * because Spotify's authentication server rejects cross-site
 * requests. In that case, authenticate with the Implicit Grant Flow
 * instead.
 *
 * [Reference](https://developer.spotify.com/web-api/authorization-guide/#client-credentials-flow).
 *
 * @param {string} clientId - Client ID.
 * @param {string} clientSecret - Client secret key.
 * @param {string} [grantType] - Grant type, default "client_credentials".
 * @return {Promise | JSON} An access token response.
 */
SpotifyAuthenticator.prototype.clientsCredentialsFlow = function (clientId, clientSecret, grantType) {
  clientId = clientId || this.clientId
  clientSecret = clientSecret || this.clientSecret
  grantType = grantType || 'client_credentials'
  var auth = 'Basic ' + base64.encode(clientId + ':' + clientSecret)
  var uri = 'https://accounts.spotify.com/api/token'
  return http.json(uri, {
    method: 'POST',
    headers: {
      Authorization: auth
    },
    form: {
      'grant_type': grantType
    }
  })
}

/**
 * Authenticate with the Implicit Grant Flow.
 *
 * Returns a URI that the calling web application can use to redirect
 * the user to a Spotify login screen. After the user has logged in,
 * Spotify redirects back to the web application with an access token
 * (included in the hash fragment of the URI). That token can then be
 * passed to this class.
 *
 * [Reference](https://developer.spotify.com/web-api/authorization-guide/#implicit-grant-flow).
 *
 * @param {string} uri - Redirect URI.
 * @param {string} [clientId] - Client ID.
 * @return {string} An authentication URI.
 */
SpotifyAuthenticator.prototype.implicitGrantFlow = function (uri, clientId) {
  clientId = clientId || this.clientId
  var url = 'https://accounts.spotify.com/authorize'
  url += '/' +
    '?client_id=' + encodeURIComponent(clientId) +
    '&response_type=' + encodeURIComponent('token') +
    '&redirect_uri=' + encodeURIComponent(uri)
  return url
}

/**
 * Refresh the bearer access token.
 *
 * @return {Promise | string} A new bearer access token,
 * or the empty string if not available.
 */
SpotifyAuthenticator.prototype.refreshToken = function () {
  return this.clientsCredentialsFlow().then(function (response) {
    if (response &&
        response.access_token) {
      this.token = response.access_token
    }
    return this.token
  })
}

/**
 * Obtain a bearer access token.
 *
 * @return {Promise | string} A bearer access token,
 * or the empty string if not available.
 */
SpotifyAuthenticator.prototype.getToken = function () {
  if (this.token) {
    return Promise.resolve(this.token)
  } else {
    return this.refreshToken()
  }
}

module.exports = SpotifyAuthenticator