I use the GitHub API a lot to write example codes. There are many oAuth libs written in Swift, but they're too heavy for my use. I just want to use only GitHub API, not require OAuth 1, refresh token, etc.
Today, let's try GitHub login from scratch!
Create oAuth application on GitHub (https://github.com/settings/applications/new) and note down your client id, client secret.
The callback URL is https://exmaple.com/
.
Main.stroyboard
.iPhone 4.7-inch
size for simulated metrics on attributes inspector.
Button
from object library.
View Controller
from object library.
Present Modally
.
GitHubLoginFromScratch
and select New File...
.SignInViewController
.
Declare delegate and constants.
class SignInViewController: UIViewController, UIWebViewDelegate {
let clientId = "YOUR_CLIENT_ID"
let clientSecret = "YOUR_CLIENT_SECRET"
Add delegate method for hook http request. If url is example.com
(callback URL), extract a autorization code and send a request to get access token.
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if let url = request.URL where url.host == "example.com" {
if let code = url.query?.componentsSeparatedByString("code=").last {
let urlString = "https://github.com/login/oauth/access_token"
if let tokenUrl = NSURL(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" : clientId,
"client_secret" : clientSecret,
"code" : code
]
req.HTTPBody = try? NSJSONSerialization.dataWithJSONObject(params, options: [])
let task = NSURLSession.sharedSession().dataTaskWithRequest(req) { data, response, error in
if let data = data {
do {
if let content = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: AnyObject] {
if let accessToken = content["access_token"] as? String {
self.getUser(accessToken)
}
}
} catch {}
}
}
task.resume()
}
}
return false
}
return true
}
This getUser
method is a test for access token.
Adding Authorization: token ACCESS_TOKEN
to HTTP Header to use GitHub API.
func getUser(accessToken: String) {
let urlString = "https://api.github.com/user"
if let url = NSURL(string: urlString) {
let req = NSMutableURLRequest(URL: url)
req.addValue("application/json", forHTTPHeaderField: "Accept")
req.addValue("token \(accessToken)", forHTTPHeaderField: "Authorization")
let task = NSURLSession.sharedSession().dataTaskWithRequest(req) { data, response, error in
if let data = data {
if let content = String(data: data, encoding: NSUTF8StringEncoding) {
dispatch_async(dispatch_get_main_queue()) {
print(content)
self.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
}
}
}
}
task.resume()
}
}
Build and then run the current scheme
or press command + R
key.
If we successfully sign in, we can see the following messages.
{"login":"tnantoka","id":213169,"avatar_url":"https://avatars.githubusercontent.com/u/213169?v=3","gravatar_id":"","url":"https://api.github.com/users/tnantoka","html_url":"https://github.com/tnantoka","followers_url":"https://api.github.com/users/tnantoka/followers","following_url":"https://api.github.com/users/tnantoka/following{/other_user}","gists_url":"https://api.github.com/users/tnantoka/gists{/gist_id}","starred_url":"https://api.github.com/users/tnantoka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tnantoka/subscriptions","organizations_url":"https://api.github.com/users/tnantoka/orgs","repos_url":"https://api.github.com/users/tnantoka/repos","events_url":"https://api.github.com/users/tnantoka/events{/privacy}","received_events_url":"https://api.github.com/users/tnantoka/received_events","type":"User","site_admin":false,"name":"Tatsuya Tobioka","company":null,"blog":"http://tnantoka.com/","location":"Tokyo, Japan","email":"tnantoka@bornneet.com","hireable":true,"bio":null,"public_repos":108,"public_gists":6,"followers":56,"following":0,"created_at":"2010-03-01T14:24:36Z","updated_at":"2015-11-12T02:04:52Z"}
That's all for today.