Skip to content

Instantly share code, notes, and snippets.

@collinalexbell
Created July 2, 2018 00:55
Show Gist options
  • Save collinalexbell/12016a5c9f513dc54a991187785742e6 to your computer and use it in GitHub Desktop.
Save collinalexbell/12016a5c9f513dc54a991187785742e6 to your computer and use it in GitHub Desktop.
Example Oauth
(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