IOS app not login -Chapter 19 API Authentication Part 2

Hello,

 I have followed the tutorial till  chapter 19 page 308 .

Build and run IOS app .
When I input user name ,password and tabbed login it fails .
After I go through the code in Auth.swift and LoginTableViewController.swift , There are not any wrong , it’s same as tutorial . Also checked the response in Rested. It response “OK” as below.
Appreciated if you could advise.

Response from API in Rested App
https:///api/users/login
and set Authorization (user:admin, password: password) .
It response status code "200 OK "as below.

Accept: /
Accept-Encoding: gzip, deflate
Authorization: Basic YWRtaW46cGFzc3dvcmQ=
Accept-Language: en-us

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Content-Length: 128
Date: Fri, 27 Jul 2018 19:46:25 GMT

{
“token”: “lCEWJwMq1d+YnjqF3F2EqA==”,
“id”: “20C2905B-49DF-4DAD-99FC-72868EA52990”,
“userID”: “xxxxxxxxxxxxxxx”
}

What is the error you get in your Vapor app when you try and login from iOS?

I have got this message error after login user:admin and password : password.

"Error
Could not login. Check your
credentials and try again.
"

Are you setting the correct headers etc in the iOS app? If you debug your Vapor app in the middleware, can you work out where it fails?

Hello Tim,

Thanks for your advice.
I have debugged using print command .
It look like data is nil, because it print out “failure” as below.

In Auth.swift:

var loginRequest = URLRequest(url:url)
//5
loginRequest.addValue(“Basic(loginString)”, forHTTPHeaderField: “Authorization”)
loginRequest.httpMethod = “POST”
print(loginRequest.debugDescription)
print(loginRequest.allHTTPHeaderFields)
//6
let dataTask = URLSession.shared
.dataTask(with: loginRequest) { data, response, _ in
//7

guard let httpResponse = response as? HTTPURLResponse,
  httpResponse.statusCode == 200,
  let jsonData = data else {
     print("failure")
       completion(.failure)
    return
  }

Output

https://myweb.com/api/users/login
Optional([“Authorization”: “BasicYWRtaW46cGFzc3dvcmQ=”])
failure

@0xtim Can you please help with this when you get a chance? Thank you - much appreciated! :]

@thammaporn you’re missing a space between Basic and the login string. Your code should look like:

loginRequest.addValue(“Basic \(loginString)”, forHTTPHeaderField: “Authorization”)

@0xtim
Solved!!
Thanks very much.

1 Like

I have the same question. I have completed the book up to this point. In Postman, I get a 200 response, but in the app I get 401. My code is correct space after “Basic” etc. Are there any other solutions you can think of? I am stuck :frowning:

@0xtim Can you please help with this when you get a chance? Thank you - much appreciated! :]

I had the same problem, because the starter project contains the url “rw-til.vapor.cloud” in some files. After changing all of them in the iOS project, it worked.

@ericlm Thank you for sharing your solution - much appreciated! :]

@reeder3240 did @ericlm solution help? If not can you debug the request in the app to make sure it’s sending it to your server? Then does it work in Rested?

All my urls are correct, so it wasn’t that. Here is my debug log:

loginRequest: https://nr-til.vapor.cloud/api/users/login
response: Optional(<NSHTTPURLResponse: 0x600000afe460> { URL: https://nr-til.vapor.cloud/api/users/login } { Status Code: 401, Headers {
“Content-Length” = (
58
);
“Content-Type” = (
“application/json; charset=utf-8”
);
Date = (
“Thu, 07 Feb 2019 16:48:18 GMT”
);
Server = (
nginx
);
“Strict-Transport-Security” = (
“max-age=15724800;”
);
} })
path: https://nr-til.vapor.cloud/api/users/login

Yes, it works with Postman (rested).

Edit: In Postman, I can log in just fine with admin account. Then when I pass that token in the app, I can log in fine. Then if I create a new user, remove that token, and try to log in with new user, I get 401 error again. In the app, I simply do not get a token passed back to me from the log in page.

@reeder3240 in the headers I don’t see an Authorization header, which should be there. Are you definitely setting it?

         var loginRequest = URLRequest(url: url)

        loginRequest.addValue("Basic \(loginString)", forHTTPHeaderField: "Authorization")
        loginRequest.httpMethod = "POST"

I am setting it. Does this look correct?

Full log:
loginRequest: https://nr-til.vapor.cloud/api/users/login/
response: Optional(<NSHTTPURLResponse: 0x600002660c60> { URL: https://nr-til.vapor.cloud/api/users/login/ } { Status Code: 401, Headers {
“Content-Length” = (
58
);
“Content-Type” = (
“application/json; charset=utf-8”
);
Date = (
“Fri, 08 Feb 2019 17:13:59 GMT”
);
Server = (
nginx
);
“Strict-Transport-Security” = (
“max-age=15724800;”
);
} })
path: https://nr-til.vapor.cloud/api/users/login/,
headerFields: Optional([“Authorization”: “Basic 20 bytes”]),
Authorization: Optional(“Basic 20 bytes”)

Yep that looks correct. So next questions:

  • How are you creating loginString?
  • The username and password are definitely correct right? (Always worth checking)
  • How did you create the user in Vapor Cloud?
  • Does it work with Rested
  • I’m assuming it all works when running locally right?

loginString is correct.

This is how I created the user:
struct AdminUser: Migration {
typealias Database = PostgreSQLDatabase

static func prepare(on connection: PostgreSQLConnection) -> Future<Void> {
    let password = try? BCrypt.hash("password")
    guard let hashedPassword = password else {
        fatalError("Failed to create admin user")
    }

    let user = User(name: "Admin",
                    username: "admin",
                    password: hashedPassword)
    return user.save(on: connection).transform(to: ())
}

static func revert(on connection: PostgreSQLConnection) -> Future<Void> {
    
    return .done(on: connection)
}

}

when i run a GET on api/users it returns this user(of course no password).

It works on Rested and locally.

Have you tried resetting the database? Everything looks valid, so I don’t know quite what’s going on. When you say loginString is correct, how are you creating it? Does the final project from the book chapter work if you change the URLs?