Created
November 5, 2016 21:53
-
-
Save arohner/8d94ee5704b1c0c1b206186525d9f7a7 to your computer and use it in GitHub Desktop.
Clojure example of accessing google APIs directly
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
(ns example.api.google | |
(:require [cemerick.url :as url] | |
[cheshire.core :as json] | |
[clj-jwt.core :as jwt] | |
[clj-jwt.key :as key] | |
[clj-time.core :as time] | |
[clj-http.client :as http] | |
[clojure.string :as str]) | |
(:import java.io.StringReader)) | |
;;; Example code for calling Google apis using a service account. | |
(defn load-creds | |
"Takes a path to a service account .json credentials file" | |
[secrets-json-path] | |
(-> secrets-json-path slurp (json/parse-string keyword))) | |
;; list of API scopes requested, e.g. https://developers.google.com/admin-sdk/directory/v1/guides/authorizing | |
(def scopes ["https://www.googleapis.com/auth/admin.directory.user" | |
"https://www.googleapis.com/auth/admin.directory.group"]) | |
(defn create-claim [creds & [{:keys [sub] :as opts}]] | |
(let [claim (merge {:iss (:client_email creds) | |
:scope (str/join " " scopes) | |
:aud "https://www.googleapis.com/oauth2/v4/token" | |
:exp (-> 1 time/hours time/from-now) | |
:iat (time/now)} | |
(when sub | |
;; when using the Admin API, delegating access, :sub may be needed | |
{:sub sub}))] | |
(-> claim jwt/jwt (jwt/sign :RS256 (-> creds :private_key (#(StringReader. %)) (#(key/pem->private-key % nil)))) (jwt/to-str)))) | |
(defn request-token [creds & [{:keys [sub] :as opts}]] | |
(let [claim (create-claim creds opts) | |
resp (http/post "https://www.googleapis.com/oauth2/v4/token" {:form-params {:grant_type "urn:ietf:params:oauth:grant-type:jwt-bearer" | |
:assertion claim} | |
:as :json})] | |
(when (= 200 (-> resp :status)) | |
(-> resp :body :access_token)))) | |
;; Call request-token to make an API call to google to create a new access token, using creds. Access-tokens are valid for 1 hour after creating. Pass the received token to API calls. | |
(defn api-req [{:keys [] :as request} token] | |
(http/request (-> request | |
(assoc-in [:headers "Authorization"] (str "Bearer " token)) | |
(assoc :as :json)))) |
Thank you for posting this-it saved me a lot of time.
(ns
example.google.auth
(:require
[cheshire.core :as json]
[babashka.curl :as curl]
[buddy.core.keys :as keys]
[buddy.sign.jwt :as jwt]
[clojure.string :as str])
(:import java.io.StringReader))
(defn load-creds
"Takes a path to a service account .json credentials file"
[secrets-json-path]
(-> secrets-json-path slurp (json/parse-string keyword)))
(defn
create-claim
[creds & [{:keys [sub scopes] :as opts}]]
(let [now (java.time.Instant/now)
claim (merge
{:iss (:client_email creds)
:scope (str/join " " scopes)
:aud "https://oauth2.googleapis.com/token"
:exp (+ (.getEpochSecond now) (* 60 30))
:iat (.getEpochSecond now)}
(when
sub
;; when using the Admin API, delegating access, :sub may be needed
{:sub sub}))]
(jwt/sign
claim
(keys/str->private-key
(:private_key creds))
{:alg :rs256})))
(defn request-token [creds & [{:keys [sub] :as opts}]]
(let [claim (create-claim creds opts)
resp (curl/post
"https://www.googleapis.com/oauth2/v4/token"
{:form-params
{:grant_type "urn:ietf:params:oauth:grant-type:jwt-bearer"
:assertion claim}
:as :json})]
(if (= 200 (-> resp :status))
(-> resp :body (json/decode keyword) :access_token)
resp)))
(defn
auth
[request token]
(->
request
(assoc-in [:headers "Authorization"] (str "Bearer " token))
(assoc :as :json)))
(comment
(request-token
(load-creds credential-path)
{:scopes ["https://www.googleapis.com/auth/spreadsheets.readonly"]}))
I needed to adapt a bit also not using outdated clj-time
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thanks for saving my time!