skip to Main Content

I’m trying to follow Last.fm’s tutorial to consume their API in an iOS app (using Swift), but I don’t know what’s wrong with my code. They ask to do something called Last.fm method signature which I’m not understanding how to insert into my program. Here is the link to the tutorial I try to follow: https://www.last.fm/api/mobileauth

Here is my current code:

import UIKit

struct LoginRequestBody: Codable { 
    var username: String 
    var password: String 
    var api_key: String 
    var api_sig: String 
}

enum AuthenticationError: Error { 
    case invalidCredentials 
    case custom(errorMessage: String) 
}

class APIService {
    func requestAPI(username: String, password: String, api_key: String, api_sig: String) {
        guard let url = URL(string: "http://www.last.fm/api/auth/?api_key=xxx") else {
            return
        }
        
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = "POST"
        
        let body = LoginRequestBody(username: username, password: password, api_key: api_key, api_sig: api_sig)
        let bodyStr = [
            "username": "(body.username)",
            "password": "(body.password)",
            "api_key": "(body.api_key)",
            "api_sig": "(body.api_sig)"]
        
        urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: bodyStr, options: .fragmentsAllowed)
        
        let task = URLSession.shared.dataTask(with: urlRequest) { data, _, error in
            guard let data = data, error == nil else {
                return
            }
            
            do {
                let response = try JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed)
                print(response)
            } catch {
                print(error)
            }
        }
        task.resume()
    }
}

2

Answers


  1. You are seeing the error you mentioned in your comments because you try to connect to an endpoint using http instead of https and Apples App Transport Security mechanism blocks you from doing that.

    You have two options (maybe more :))

    1. See if Last.fm supports https instead and if they to, then use that
    2. Allow your app to use http instead. You do so by adding this to your info.plist
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
    

    Before you do so though, please see also this great answer describing all the risks you take if you use http over https

    Login or Signup to reply.
  2. You should definitely use the secure https://ws.audioscrobbler.com/2.0/auth.getMobileSession endpoint like it is mentioned in the documentation. That is also important because you send sensitive data over the wire like the user’s password.

    Next you should generate the body of your POST request.

    If you struggle to generate the signature, here’s how:

    1. Order all parameters (i.e. key-value pairs) of your request and the endpoint method alphabetically, e.g.
      • api_key -> your_key
      • method -> auth.getMobileSession
      • password -> somebodys_password
      • username -> somebody
    2. Concatenate them to one string like the schema key1value1key2...keyNvalueN, e.g.
      • api_keyyour_keymethodauth.getMobileSessionpassword...usernamesomebody
    3. Append your API secret (let’s assume it has the value apisecret) to that string (and only that value apisecret)
      • api_keyyour_keymethodauth.getMobileSessionpassword...usernamesomebodyapisecret
      • You’ve got that API secret when you registered your App at last.fm, along with your API key
    4. Generate the MD5 hash of that string
      • not sure how this would be done in Swift but Google and Stackoverflow are your friends
      • be sure your have correctly UTF-8 encoded all the strings
    5. This hash is the signature you will send as api_sig in your request

    This is also the way to generate the signature for other API calls.

    Note: when you use the getMobileSession approach you won’t redirect the user to a last.fm page where they could allow your app to access their profile. Instead you are sending directly the user’s credentials to last.fm to authenticate.

    Note: for me the body of such a HTTP POST request was assembled like key1=value1&key2=value2&... maybe Swift is doing this internally already.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search