From fb0ded3ba9e8b1d3c2cb10942119874d1e8d0251 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Aleksandr Vityazev Date: Thu, 25 Nov 2021 15:33:57 +0300 Subject: [PATCH 04/11] * oauth2: Remove oauth2--url-http-handle-authentication-hack (oauth2-auth-and-store): Check the token expiration date. (oauth2-token): Add new slots. --- oauth2.el | 91 +++++++++++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 50 deletions(-) diff --git a/oauth2.el b/oauth2.el index fff89af..31da145 100644 --- a/oauth2.el +++ b/oauth2.el @@ -108,6 +108,8 @@ Return the code provided by the service." (access-token "" :read-only t) (refresh-token "" :read-only t) (token-url "" :read-only t) + (expires-in "" :read-only t) + (created-at "" :read-only t) (access-response "" :read-only t)) (cl-defun oauth2-request-access (token-url client-id client-secret code &optional @@ -155,6 +157,8 @@ TOKEN should be obtained with `oauth2-request-access'." :client-secret client-secret :access-token (cdr (assoc 'access_token response)) :refresh-token (cdr (assoc 'refresh_token response)) + :expires-in (cdr (assoc 'expires_in response)) + :created-at (cdr (assoc 'created_at response)) :token-url token-url :access-response response))) (when plstore @@ -169,7 +173,8 @@ TOKEN should be obtained with `oauth2-request-access'." new-token))) ;;;###autoload -(defun oauth2-auth (auth-url token-url client-id client-secret &optional scope state redirect-uri) +(defun oauth2-auth + (auth-url token-url client-id client-secret &optional scope state redirect-uri) "Authenticate application via OAuth2 at AUTH-URL and TOKEN-URL. CLIENT-ID is the client id provided by the provider. CLIENT-SECRET is the client secret associated with your CLIENT-ID. @@ -195,6 +200,8 @@ Return an `oauth2-token' structure." :client-secret client-secret :access-token (cdr (assoc 'access_token response)) :refresh-token (cdr (assoc 'refresh_token response)) + :expires-in (cdr (assoc 'expires_in response)) + :created-at (cdr (assoc 'created_at response)) :token-url token-url :access-response response))) @@ -204,7 +211,8 @@ This allows to store the token in an unique way." (secure-hash 'md5 (concat auth-url token-url scope))) ;;;###autoload -(defun oauth2-auth-and-store (auth-url token-url client-id client-secret scope &optional state redirect-uri) +(defun oauth2-auth-and-store + (auth-url token-url client-id client-secret scope &optional state redirect-uri) "Request access to a resource and store it using `plstore'. If the token has not yet been saved in plsote, then authenticate the application via OAuth2 using the AUTH-URL, TOKEN-URL and after that @@ -219,17 +227,25 @@ uses to maintain state between the request and redirect response. Return an `oauth2-token' structure." (if-let ((plstore (plstore-open oauth2-token-file)) (id (oauth2-compute-id auth-url token-url scope)) - (plist (cdr (plstore-get plstore id)))) + (plist (cdr (plstore-get plstore id))) + (expires (cdr (assoc 'expires_in (plist-get plist :access-response)))) + (created (cdr (assoc 'created_at (plist-get plist :access-response)))) + (current-time (time-convert nil 'integer)) + (token (make-oauth2-token :plstore plstore + :plstore-id id + :client-id client-id + :client-secret client-secret + :access-token (plist-get plist :access-token) + :refresh-token (plist-get plist :refresh-token) + :expires-in expires + :created-at created + :token-url token-url + :access-response (plist-get plist :access-response)))) ;; Check if we found something matching this access ;; We did, return the token object - (make-oauth2-token :plstore plstore - :plstore-id id - :client-id client-id - :client-secret client-secret - :access-token (plist-get plist :access-token) - :refresh-token (plist-get plist :refresh-token) - :token-url token-url - :access-response (plist-get plist :access-response)) + (if (< current-time (+ expires created)) + token + (oauth2-refresh-access token)) (let ((token (oauth2-auth auth-url token-url client-id client-secret scope state redirect-uri))) (plstore-put plstore id nil `(:access-token @@ -247,48 +263,25 @@ Return an `oauth2-token' structure." (if (string-match-p "\?" url) "&" "?") "access_token=" (oauth2-token-access-token token))) -(defvar oauth2--url-advice nil) -(defvar oauth--token-data) - (defun oauth2-authz-bearer-header (token) "Return `Authoriztions: Bearer' header with TOKEN." (cons "Authorization" (format "Bearer %s" token))) -(defun oauth2-extra-headers (extra-headers) +(defun oauth2-extra-headers (token extra-headers) "Return EXTRA-HEADERS with `Authorization: Bearer' added." - (cons (oauth2-authz-bearer-header (oauth2-token-access-token (car oauth--token-data))) + (cons (oauth2-authz-bearer-header (oauth2-token-access-token token)) extra-headers)) - -;; FIXME: We should change URL so that this can be done without an advice. -(defun oauth2--url-http-handle-authentication-hack (orig-fun &rest args) - (if (not oauth2--url-advice) - (apply orig-fun args) - (let ((url-request-method url-http-method) - (url-request-data url-http-data) - (url-request-extra-headers - (oauth2-extra-headers url-http-extra-headers))) - (oauth2-refresh-access (car oauth--token-data)) - (url-retrieve-internal (cdr oauth--token-data) - url-callback-function - url-callback-arguments) - ;; This is to make `url' think it's done. - t))) - -(advice-add 'url-http-handle-authentication :around - #'oauth2--url-http-handle-authentication-hack) - ;;;###autoload -(defun oauth2-url-retrieve-synchronously (token url &optional request-method request-data request-extra-headers) +(defun oauth2-url-retrieve-synchronously + (token url &optional request-method request-data request-extra-headers) "Retrieve an URL synchronously using TOKEN to access it. TOKEN can be obtained with `oauth2-auth'." - (let* ((oauth--token-data (cons token url))) - (let ((oauth2--url-advice t) ;Activate our advice. - (url-request-method request-method) - (url-request-data request-data) - (url-request-extra-headers - (oauth2-extra-headers request-extra-headers))) - (url-retrieve-synchronously url)))) + (let ((url-request-method request-method) + (url-request-data request-data) + (url-request-extra-headers + (oauth2-extra-headers token request-extra-headers))) + (url-retrieve-synchronously url))) ;;;###autoload (defun oauth2-url-retrieve (token url callback &optional @@ -298,13 +291,11 @@ TOKEN can be obtained with `oauth2-auth'." TOKEN can be obtained with `oauth2-auth'. CALLBACK gets called with CBARGS when finished. See `url-retrieve'." ;; TODO add support for SILENT and INHIBIT-COOKIES. How to handle this in `url-http-handle-authentication'. - (let* ((oauth--token-data (cons token url))) - (let ((oauth2--url-advice t) ;Activate our advice. - (url-request-method request-method) - (url-request-data request-data) - (url-request-extra-headers - (oauth2-extra-headers request-extra-headers))) - (url-retrieve url callback cbargs)))) + (let ((url-request-method request-method) + (url-request-data request-data) + (url-request-extra-headers + (oauth2-extra-headers token request-extra-headers))) + (url-retrieve url callback cbargs))) (provide 'oauth2) -- 2.34.0