# mcias-client (Common Lisp) Common Lisp client library for the [MCIAS](../../README.md) identity and access management API. ## Requirements - SBCL 2.x (primary), CCL (secondary) - Quicklisp ## Installation Place the `clients/lisp/` directory on ASDF's central registry or load it via Quicklisp local-projects: ```sh ln -s /path/to/mcias/clients/lisp ~/.quicklisp/local-projects/mcias-client ``` Then in your Lisp image: ```lisp (ql:quickload :mcias-client) ``` ## Quick Start ```lisp (use-package :mcias-client) ;; Connect to the MCIAS server. (defvar *client* (make-client "https://auth.example.com")) ;; Authenticate. (multiple-value-bind (token expires-at) (login *client* "alice" "s3cret") (format t "token expires at ~A~%" expires-at)) ;; The token is stored in the client automatically. (let ((accounts (list-accounts *client*))) (format t "~A accounts~%" (length accounts))) ;; Revoke the token when done. (logout *client*) ``` ## Custom CA Certificate ```lisp (defvar *client* (make-client "https://auth.example.com" :ca-cert "/etc/mcias/ca.pem")) ``` ## Error Handling All functions signal typed conditions on error: ```lisp (handler-case (login *client* "alice" "wrongpass") (mcias-auth-error (e) (format t "auth failed: ~A~%" (mcias-error-message e))) (mcias-forbidden-error (e) (format t "forbidden: ~A~%" (mcias-error-message e))) (mcias-not-found-error (e) (format t "not found: ~A~%" (mcias-error-message e))) (mcias-input-error (e) (format t "bad input: ~A~%" (mcias-error-message e))) (mcias-conflict-error (e) (format t "conflict: ~A~%" (mcias-error-message e))) (mcias-server-error (e) (format t "server error ~A: ~A~%" (mcias-error-status e) (mcias-error-message e)))) ``` All condition types are subclasses of `mcias-error`, which has slots: - `mcias-error-status` — HTTP status code (integer) - `mcias-error-message` — server error message (string) ## `validate-token` Return Value `validate-token` returns a property list. The `:valid` key is `T` if the token is valid, `NIL` otherwise (never raises an error for an invalid token): ```lisp (let ((result (validate-token *client* some-token))) (if (getf result :valid) (format t "valid; sub=~A~%" (getf result :sub)) (format t "invalid~%"))) ``` ## Running Tests ```sh sbcl --non-interactive \ --eval '(require :asdf)' \ --eval "(push #P\"$(pwd)/\" asdf:*central-registry*)" \ --eval '(ql:quickload :mcias-client/tests :silent t)' \ --eval '(mcias-client-tests:run-all-tests)' \ --eval '(uiop:quit)' ```