Property definitions

popcorn $ GithubOAuthCallBack :: defaultinit
# Get the authentification code and translate it to an access token.
class GithubOAuthCallBack
	super Handler

	# The client ID delivered by GitHub for your application.
	#
	# See https://github.com/settings/applications/new.
	var client_id: String is writable

	# The client secret you received from Github when your registered your application.
	var client_secret: String is writable

	# The URL in your application where users will be sent after authorization.
	#
	# If `null`, the URL used in application registration will be used.
	#
	# See https://developer.github.com/v3/oauth/#redirect-urls.
	var redirect_uri: nullable String is writable

	# An optional and unguessable random string.
	#
	# It is used to protect against cross-site request forgery attacks.
	var state: nullable String is writable

	# Github OAuth token URL.
	var token_url = "https://github.com/login/oauth/access_token" is writable

	# Header map sent with the OAuth token request.
	var headers: HeaderMap do
		var map = new HeaderMap
		map["Accept"] = "application/json"
		return map
	end

	# Build the OAuth post data.
	fun build_auth_body(code: String): HeaderMap do
		var map = new HeaderMap
		map["client_id"] = client_id
		map["client_secret"] = client_secret
		map["code"] = code
		var redirect_uri = self.redirect_uri
		if redirect_uri != null then map["redirect_uri"] = redirect_uri
		var state = self.state
		if state != null then map["state"] = state
		return map
	end

	redef fun get(req, res) do
		# Get OAuth code
		var code = req.string_arg("code")
		if code == null then
			res.error 401
			return
		end

		# Exchange it for an access token
		var access_token = request_access_token(code)
		if access_token == null then
			res.error 401
			return
		end

		# Load github user
		var gh_api = new GithubAPI(access_token)
		var user = gh_api.get_auth_user
		if user == null then
			res.error 401
			return
		end
		# Set session and redirect to user page
		var session = req.session
		if session == null then
			res.error 500
			return
		end
		session.user = user
		res.redirect redirect_uri or else "/"
	end

	# Request an access token from an access `code`.
	private fun request_access_token(code: String): nullable String do
		var request = new CurlHTTPRequest(token_url)
		request.headers = headers
		request.data = build_auth_body(code)
		var response = request.execute
		return parse_token_response(response)
	end

	# Parse the Github access_token response and extract the access_token.
	private fun parse_token_response(response: CurlResponse): nullable String do
		if response isa CurlResponseFailed then
			print "Request to Github OAuth failed"
			print "Requested URI: {token_url}"
			print "Error code: {response.error_code}"
			print "Error msg: {response.error_msg}"
			return null
		else if response isa CurlResponseSuccess then
			var obj = response.body_str.parse_json
			if not obj isa JsonObject then
				print "Error: Cannot parse json response"
				print response.body_str
				return null
			end
			var access_token = obj.get_or_null("access_token")
			if not access_token isa String then
				print "Error: No `access_token` key in response"
				print obj.to_json
				return null
			end
			return access_token
		end
		return null
	end
end
lib/popcorn/pop_auth.nit:138,1--251,3