Created
July 2, 2018 00:55
-
-
Save collinalexbell/12016a5c9f513dc54a991187785742e6 to your computer and use it in GitHub Desktop.
Example Oauth
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ql:quickload :hunchentoot) | |
(ql:quickload :cl-json) | |
(ql:quickload :quri) | |
(ql:quickload :drakma) | |
(ql:quickload :babel) | |
(ql:quickload :cl-arrows) | |
(defpackage :aristotle.oauth | |
(:use :cl :cl-json :cl-arrows)) | |
(in-package :aristotle.oauth) | |
(defparameter *secrets* nil) | |
(defclass oauth-flow () | |
((client-id :initarg :id) | |
(client-secret :initarg :secret) | |
(auth-uri :initarg :auth-uri) | |
(token-uri :initarg :token-uri) | |
(scope :initarg :scope) | |
(redirect-uri :initarg :redirect) | |
(auth-code) | |
(access-token))) | |
(defun setf-oauth-flow (oauth-flow) | |
(defparameter *current-oauth-flow* oauth-flow) | |
oauth-flow) | |
(defun initiate-oauth () | |
(-> (read-secrets "./data/keys/google_secrets.json") | |
(make-oauth-flow-from-secrets) | |
(setf-oauth-flow) | |
(callback-init) | |
(generate-auth-request-uri) | |
(quri:render-uri))) | |
(defun make-oauth-flow-from-secrets (secrets | |
&optional (scope "youtube.force-ssl")) | |
(make-instance | |
'oauth-flow | |
:id (cdr (assoc :client--id (cdr (assoc :web secrets)))) | |
:secret (cdr (assoc :client--secret (cdr (assoc :web secrets)))) | |
:auth-uri (cdr (assoc :auth--uri (cdr (assoc :web secrets)))) | |
:token-uri (cdr (assoc :token--uri (cdr (assoc :web secrets)))) | |
:scope (concatenate 'string "https://www.googleapis.com/auth/" scope) | |
:redirect (first (cdr (assoc :redirect--uris (cdr (assoc :web secrets))))))) | |
(defun oauth-flow-auth-uri-obj (oauth-flow) | |
(quri:uri (slot-value oauth-flow 'auth-uri))) | |
(defun generate-auth-request-uri (oauth-flow) | |
(let (( uri-obj (oauth-flow-auth-uri-obj oauth-flow))) | |
(setf (quri:uri-query-params uri-obj) | |
`(("client_id" . ,(slot-value oauth-flow 'client-id)) | |
("redirect_uri" . ,(slot-value oauth-flow 'redirect-uri)) | |
("scope" . ,(slot-value oauth-flow 'scope)) | |
("access_type" . "offline") | |
("state" . "state_parameter_passthrough_value") | |
("response_type" . "code"))) | |
uri-obj)) | |
(defun file-get-contents (filename) | |
(with-open-file (stream filename) | |
(let ((contents (make-string (file-length stream)))) | |
(read-sequence contents stream) | |
contents))) | |
(defun read-secrets (filename) | |
(setf *secrets* | |
(json:decode-json-from-string | |
(file-get-contents filename)))) | |
(hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 4242)) | |
(defun callback-init (oauth-flow) | |
(hunchentoot:define-easy-handler (cb :uri "/auth/google/callback") (code) | |
(setf (hunchentoot:content-type*) "text/plain") | |
(setf (slot-value oauth-flow 'auth-code) code) | |
(format nil "auth finished!!: ~a" code)) | |
oauth-flow) | |
(defun decode-json-from-octets (octets) | |
(json:decode-json-from-string | |
(babel:octets-to-string octets))) | |
(defun request-access-token (oauth-flow) | |
(decode-json-from-octets | |
(drakma:http-request | |
(slot-value oauth-flow 'token-uri) | |
:method :post | |
:parameters | |
`(("grant_type" . "authorization_code") | |
("client_id" . ,(slot-value oauth-flow 'client-id)) | |
("client_secret" . ,(slot-value oauth-flow 'client-secret)) | |
("redirect_uri" . ,(slot-value oauth-flow 'redirect-uri)) | |
("code" . ,(slot-value oauth-flow 'auth-code)))))) | |
(defun parse-access-token-response (token-response oauth-flow) | |
(setf (slot-value oauth-flow 'access-token) | |
(cdr (assoc :access--token token-response)))) | |
(defun finish-oauth () | |
(-> (request-access-token *current-oauth-flow*) | |
(parse-access-token-response *current-oauth-flow*))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment