Reputation: 45
I am trying to understand how oauth authentication with GITHUB works in case of IOS Apps.
I am developing an IOS App and want to use GITHUB for login authentication.
Here is flow of my app.
User registration - This is an offline process and happens outside of my app. When I create an account for user, I ask them to provide their GITHUB email address. I store this email address in our DB as userid for that user.
Get access token from GITHUB - when user opens our app we direct them to https://github.com/login/oauth/authorize using webview. Once user successfully login to GITHUB account I use https://github.com/login/oauth/access_token to get access token.
Get email address using access token - I am using https://api.github.com/user/emails to get email address of logged account using access token I got in step 2.
Verify email address: I verify email address I got in step3 against my database. If userid exists then user will be able to do transactions on our app.
Right now after GITHUB verification control is coming back to viewcontroller that has webview for GITHUB and a blank screen appears. How do I move flow to next viewcontroller ?
Here is my ViewController Code:
import UIKit
import WebKit
class Login: UIViewController, UIWebViewDelegate {
@IBOutlet weak var webview: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
let authURL = String(format: "%@?client_id=%@&redirect_uri=%@&scope=%@", arguments: [GITHUB.GITHUB_AUTHURL,GITHUB.GITHUB_CLIENT_ID,GITHUB.GITHUB_REDIRECT_URI,GITHUB.GITHUB_SCOPE])
let urlRequest = URLRequest.init(url: URL.init(string: authURL)!)
webview.loadRequest(urlRequest)
webview.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func webView(_ webview: UIWebView, shouldStartLoadWith request:URLRequest, navigationType: UIWebViewNavigationType) -> Bool{
return checkRequestForCallbackURL(request: request)
}
func checkRequestForCallbackURL(request: URLRequest) -> Bool {
//print("3. IN FUNCTION checkRequestForCallbackURL")
let requestURLString = (request.url?.absoluteString)! as String
//print("3. requestURLString=\(requestURLString)")
if requestURLString.hasPrefix(GITHUB.GITHUB_REDIRECT_URI) {
let range: Range<String.Index> = requestURLString.range(of: "?code=")!
handleGithubCode(code: requestURLString.substring(from: range.upperBound))
return false;
}
return true
}
func handleGithubCode(code: String) {
let urlString = "https://github.com/login/oauth/access_token"
if let tokenUrl = URL(string: urlString) {
let req = NSMutableURLRequest(url: tokenUrl)
req.httpMethod = "POST"
req.addValue("application/json", forHTTPHeaderField: "Content-Type")
req.addValue("application/json", forHTTPHeaderField: "Accept")
let params = [
"client_id" : GITHUB.GITHUB_CLIENT_ID,
"client_secret" : GITHUB.GITHUB_CLIENTSECRET,
"code" : code
]
req.httpBody = try? JSONSerialization.data(withJSONObject: params, options: [])
let task = URLSession.shared.dataTask(with: req as URLRequest) { data, response, error in
if let data = data {
do {
if let content = try JSONSerialization.jsonObject(with: data, options: []) as? [String: AnyObject] {
if let accessToken = content["access_token"] as? String {
self.getComposerToken(accessToken: accessToken)
}
}
} catch {}
}
}
task.resume()
}
}
func getComposerToken(accessToken: String) {
print("5. accessToken=\(accessToken)")
let def = "NO_DATA"
let composerUrl = "http://192.168.100.112/kubher/getAccessToken.php?token=\(accessToken)"
guard let url = URL(string: composerUrl) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let response = response {
//print(response)
}
if let data = data {
do {
let json = try? JSONSerialization.jsonObject(with: data, options: [])
if let dict = json as? [String: Any],
let token = dict["accessToken"] {
print("Blockchain Token:\(token)")
}
} catch {
print(error)
}
}
}.resume()
}
}
Upvotes: 2
Views: 1584
Reputation: 5052
Move to next viewcontroller depends on the architecture of your code. Try the following code based on your design. opt 1: If you need to go back to previous ViewController, just modify your getComposerToken function:
if let dict = json as? [String: Any], {
let token = dict["accessToken"] {
print("Blockchain Token:\(token)")
dispatch_async(dispatch_get_main_queue()) {
self.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
}
}
}
opt 2: On the other hand, If you are using Segue for next viewController in stoaryboard, give your segue a name(Identifier) and then follow this code:
if let dict = json as? [String: Any], {
let token = dict["accessToken"] {
print("Blockchain Token:\(token)")
dispatch_async(dispatch_get_main_queue()) {
self.performSegue(withIdentifier: "YourSegueName", sender: token)
}
}
}
Additionally, you have to override prepare method to pass data
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueName" {
let viewController = segue.destination as? YourViewController
if let token = sender as? String {
viewController?.token = token
}
}
}
}
OPT 3: If you use push view controller after creating from storyboard, you have to give your view controller an Identifier in storyboard and then you can instantiate it using and push it using:
if let dict = json as? [String: Any], {
let token = dict["accessToken"] {
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let abcViewController = storyboard.instantiateViewControllerWithIdentifier("YourControlleridentifier") as! YourViewController
YourViewController.token = token
navigationController?.pushViewController(YourViewController, animated: true)
}
}
Upvotes: 1