Group Group Group Group Group Group Group Group Group

IOS app not login -Chapter 19 API Authentication Part 2


#1

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”
}


#2

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


#3

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

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


#4

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?


#5

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


#6

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


#7

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

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

#8

@0xtim
Solved!!
Thanks very much.


#10

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:


#11

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


#12

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.


#13

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


#14

@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?


#15

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.


#16

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


#17
         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”)


#18

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?

#19

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.


#20

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?