anchor.diff:      (cl-json:decode-json-from-string
         (drakma:http-request endpoint
                              :parameters `(("alt" . "json")
  -                                         ("access_token" . ,access-token))
  -                           ))))
  -
  -(defun google-login-entry (params)
  -  (declare (ignore params))
  -  (with-context-variables (session)
  -    (let ((state (gen-state 36)))
  -      (setf (gethash :state session) state)
  -      (with-endpoints *goog-endpoint-schema*
  -        (setf (gethash :endpoint-schema session) *goog-endpoint-schema*)
  -        (multiple-value-bind (content rcode headers) (do-auth-request *goog-endpoint-schema* state)
  -          (if (< rcode 400)
  -            `(302 (:location ,(cdr (assoc :location headers))))
  -            content))))))
  -
  -(defun facebook-login-entry (params)
  -  (declare (ignore params))
  -  (let ((session (ningle:context :session))
  -        (state (gen-state 36)))
  -      (setf (gethash :state session) state)
  -      (with-endpoints *fbook-endpoint-schema*
  -        (setf (gethash :endpoint-schema session) *fbook-endpoint-schema*)
  -        (multiple-value-bind (content rcode headers uri) (do-auth-request *fbook-endpoint-schema* state)
  -          (declare (ignore headers))
  -          (if (< rcode 400)
  -            `(302 (:location ,(format nil "~a" uri)))
  -            content)))))
  -
  -(defun google-callback (login-callback)
  -  (lambda (params)
  -    (let ((received-state (cdr (string-assoc "state" params)))
  -          (code (cdr (string-assoc "code" params))))
  -      (check-state received-state
  -                   (with-context-variables (session)
  -                     (with-endpoints *goog-endpoint-schema*
  -                       (let* ((a-t (get-access-token *goog-endpoint-schema* code))
  -                              (access-token (assoc-cdr :access--token a-t)) ;; Argh
  -                              (id-token (assoc-cdr :id--token a-t))
  -                              (decoded (cljwt:decode id-token :fail-if-unsupported nil))
  -                              (user-info (get-user-info *goog-endpoint-schema* access-token)))
  -                         (setf (gethash :idtoken session) id-token
  -                               (gethash :accesstoken session) access-token
  -                               (gethash :userinfo session) user-info
  -                               (gethash :app-user session) (funcall login-callback
  -                                                                    user-info
  -                                                                    decoded
  -                                                                    access-token))
  -                         '(302 (:location "/"))
  -                         )))
  -                   '(403 '() "Out, vile imposter!")))))
  -
  -(defmacro setup-session ((session) &rest rest &key nonsense &allow-other-keys)
  -  (declare (ignorable nonsense))
  -  (cons 'progn
  -        (iterate:iterate (iterate:for key   in rest       by #'cddr )
  -                         (iterate:for value in (cdr rest) by #'cddr)
  -                         (iterate:collect `(setf (gethash ,(alexandria:make-keyword (key)) ,session) ,value)))))
  -
  -(defun facebook-callback (login-callback)
  -  (lambda (params)
  -    (let ((received-state (cdr (string-assoc "state" params)))
  -          (code (cdr (string-assoc "code" params))))
  -      (with-endpoints *fbook-endpoint-schema*
  -        (check-state received-state
  -                     (let* ((a-t (get-access-token *fbook-endpoint-schema* code))
  -                            (id-token (assoc-cdr :access--token a-t))
  -                            (user-info (get-user-info *fbook-endpoint-schema* id-token)))
  -                       (with-session-values (accesstoken userinfo idtoken app-user) (context :session)
  -                                            (setf accesstoken a-t
  -                                                  userinfo user-info
  -                                                  idtoken id-token
  -                                                  app-user (funcall login-callback user-info id-token a-t)))
  -
  -                         '(302 (:location "/")))
  -                     '(403 '() "Out, vile imposter!"))))))
  +                                         ("access_token" . ,access-token))))))
  +(defmacro auth-entry-point (name endpoint-schema)
  +  `(defun ,name (params)
  +     (declare (ignore params))
  +     (with-session-values (state endpoint-schema) (context :session)
  +       (setf state (gen-state 36)
  +             endpoint-schema ,endpoint-schema)
  +       (with-endpoints ,endpoint-schema
  +         (multiple-value-bind (content rcode headers uri) (do-auth-request ,endpoint-schema state)
  +           (declare (ignore headers))
  +           (if (< rcode 400) `(302 (:location ,(format nil "~a" uri)))
  +             content))))))
  +
  +(auth-entry-point google-login-entry *goog-endpoint-schema*)
  +(auth-entry-point facebook-login-entry *fbook-endpoint-schema*)
  +
  +(defmacro def-callback-generator (name generator-args callback-args &body body)
  +  `(defun ,name ,generator-args
  +     (lambda ,callback-args
  +       ,@body)))
  +
  +(defmacro reject-when-state-invalid (params &body body)
  +  (alexandria:with-gensyms (received-state)
  +    (alexandria:once-only (params)
  +      `(let ((,received-state (cdr (string-assoc "state" ,params))))
  +         (if (not (valid-state ,received-state))
  +           '(403 '() "Out, vile imposter!")
  +        ,@body)))))
  +
  +(defmacro auth-callback-skeleton (params (&key endpoint-schema auth-session-vars) &body body)
  +  (alexandria:with-gensyms (session)
  +    (alexandria:once-only (params endpoint-schema)
  +      `(reject-when-state-invalid ,params
  +         (with-endpoints ,endpoint-schema
  +           (my-with-context-variables ((,session session))
  +             (with-session-values ,auth-session-vars ,session
  +               ,@body)))))))
  +
  +(flet ((get-code (params) (assoc-cdr "code" params #'equal)))
  +
  +  (def-callback-generator google-callback (get-app-user-cb) (params)
  +    (auth-callback-skeleton params (:endpoint-schema *goog-endpoint-schema*
  +                                    :auth-session-vars (accesstoken userinfo idtoken app-user))
  +      (flet ((get-real-access-token (a-t) (assoc-cdr :access--token a-t))
  +             (get-id-token (a-t) (cljwt:decode (assoc-cdr :id--token a-t) :fail-if-unsupported nil)))
  +        (let* ((a-t (get-access-token *goog-endpoint-schema* (get-code params)))
  +               (access-token (get-real-access-token a-t))
  +               (id-token (get-id-token a-t))
  +               (user-info (get-user-info *goog-endpoint-schema* access-token)))
  +          (setf accesstoken access-token
  +            app-user (funcall get-app-user-cb user-info id-token access-token)
  +            idtoken id-token
  +            userinfo user-info)
  +          '(302 (:location "/"))))))
  +
  +  (def-callback-generator facebook-callback (get-app-user-cb) (params)
  +    (auth-callback-skeleton params (:endpoint-schema *fbook-endpoint-schema*
  +                                    :auth-session-vars (accesstoken userinfo idtoken app-user))
  +      (flet ((get-id-token (a-t) (assoc-cdr :access--token a-t))) ; <-- access--token is not a mistake
  +        (let* ((a-t (get-access-token *fbook-endpoint-schema* (get-code params)))
  +               (id-token (get-id-token a-t))
  +               (user-info (get-user-info *fbook-endpoint-schema* id-token)))
  +          (setf accesstoken a-t
  +            app-user (funcall get-app-user-cb user-info id-token a-t)
  +            idtoken id-token
  +            userinfo user-info)
  +          '(302 (:location "/")))))))
   
   (defun userinfo-route (params)
     (declare (ignore params))
  
positive.code: (in-package :cl-oid-connect)
  ; Should this be here?
  
  (eval-when (:compile-toplevel :execute)
    (defun vars-to-symbol-macrolets (vars obj)
      (iterate:iterate (iterate:for var in vars)
                       (iterate:collect `(,var (gethash ,(alexandria:make-keyword var) ,obj))))))
  
  (defmacro with-session-values (vars session &body body)
    (alexandria:once-only (session)
      `(symbol-macrolet ,(vars-to-symbol-macrolets vars session)
         ,@body)))
  
  (defparameter *oid* (make-instance 'ningle:<app>))
  (setf drakma:*text-content-types* (cons '("application" . "json") drakma:*text-content-types*))
  
negative.code:   (discover-endpoints *goog-endpoint-schema*
                        "https://accounts.google.com/.well-known/openid-configuration"
                        :gat #'goog-get-access-token)
    (setf (redirect-uri *goog-endpoint-schema*) "http://srv2.elangley.org:9090/oidc_callback/google"))
  
  (sheeple:defreply get-user-info ((endpoint-schema *goog-endpoint-schema*) (access-token sheeple:=string=))
    (format t "getting user data: ~a~%" "blarg")
  