### Minimal Installation Examples for Buddy Modules Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Examples of how to add individual Buddy modules to your project dependencies in project.clj. ```clojure [buddy/buddy-core "1.4.0"] ``` ```clojure [buddy/buddy-hashers "1.3.0"] ``` ```clojure [buddy/buddy-auth "2.1.0"] ``` ```clojure [buddy/buddy-sign "2.2.0"] ``` ```clojure [buddy "2.0.0"] ``` -------------------------------- ### Complete Web Application Example with Buddy Source: https://github.com/funcool/buddy/blob/master/_autodocs/integration-patterns.md This snippet demonstrates a full web application setup using Buddy for authentication and authorization. It includes JWT token handling, access control rules, and route definitions for login, user profiles, and admin access. ```clojure (ns myapp.core (:require [ring.adapter.jetty :refer [run-jetty]] [ring.middleware.session :refer [wrap-session]] [ring.middleware.session.cookie :refer [cookie-store]] [ring.middleware.params :refer [wrap-params]] [ring.middleware.json :refer [wrap-json-response]] [compojure.core :refer [defroutes POST GET]] [buddy.auth :as auth] [buddy.auth.backends.token :as token-backend] [buddy.auth.middleware :as auth-middleware] [buddy.auth.accessrules :as acl] [buddy.sign.jws :as jws] [buddy.hashers :as hashers])) ; Configuration (def jwt-secret (System/getenv "JWT_SECRET")) (def admin-users #{1 2 3}) ; Authentication backend (def token-backend (token-backend/token-backend {:token-name "Authorization" :authorizefn (fn [request token] (try (let [claims (jws/unsign token jwt-secret :hs256 {:leeway 30})] {:user-id (:sub claims) :username (:username claims) :created-at (:iat claims)}) (catch Exception e (do (println "Token verification failed:" e) nil))))})) ; Access control rules (def access-rules [{:pattern #"^/admin/.*" :rule (fn [request] (let [user (:identity request)] (contains? admin-users (:user-id user))))} {:pattern #"^/api/.*" :rule :authenticated}]) ; Route handlers (defroutes app-routes (POST "/login" request (let [{:keys [username password]} (:json-params request) user (find-user-by-username username) stored-hash (:password-hash user)] (if (and user (hashers/check password stored-hash)) (let [now (quot (System/currentTimeMillis) 1000) token (jws/sign {:sub (:id user) :username username :iat now :exp (+ now (* 24 60 60))} jwt-secret :hs256)] {:status 200 :body {:token token :user {:id (:id user) :username username}}}) {:status 401 :body {:error "Invalid credentials"}}))) (GET "/api/profile" request (if (auth/authenticated? request) (let [user (auth/identity request)] {:status 200 :body {:user user}}) {:status 401 :body {:error "Not authenticated"}})) (GET "/admin/users" request (if (auth/authenticated? request) (let [user (auth/identity request)] (if (contains? admin-users (:user-id user)) {:status 200 :body {:users (list-all-users)}} {:status 403 :body {:error "Admin access required"}})) {:status 401 :body {:error "Not authenticated"}})) (GET "/health" request {:status 200 :body {:status "ok"}})) ; Application middleware (def app (-> app-routes (auth-middleware/wrap-authorization access-rules) (auth-middleware/wrap-authentication token-backend) (auth-middleware/wrap-authorization-exception) wrap-json-response wrap-params)) (defn -main [] (println "Starting server on port 3000") (run-jetty app {:port 3000 :join? false})) ``` -------------------------------- ### Clojure Test Setup for Buddy Functions Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Defines test namespaces and includes examples for testing password hashing and JWT signing using Buddy's core functionalities. ```clojure (ns myapp.test (:require [clojure.test :refer [deftest is]] [buddy.core.hash :as hash] [buddy.hashers :as hashers] [buddy.sign.jws :as jws])) (deftest test-password-hashing (let [password "secret123" hash (hashers/encrypt password)] (is (hashers/check password hash)))) (deftest test-jwt-signing (let [claims {:user-id 123} token (jws/sign claims "secret") decoded (jws/unsign token "secret")] (is (= 123 (:user-id decoded))))) ``` -------------------------------- ### Upgrade Password Hash Example Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-hashers-api.md Demonstrates how to check if a user's password hash needs to be updated to a newer algorithm. This should be performed after a successful user login. ```clojure (defn upgrade-password-hash [user] (let [old-hash (:password-hash user) algo (hashers/get-algorithm old-hash)] (when (or (= algo :bcrypt) (hashers/needs-update? old-hash)) (println (str "Hash " algo " needs upgrade"))))) ``` -------------------------------- ### Password Hashing Examples Source: https://github.com/funcool/buddy/blob/master/_autodocs/quick-reference.md Demonstrates password hashing with different security levels using bcrypt and scrypt. Adjust iterations for development, production, or high-security needs. ```clojure ; Development (fast) (hashers/encrypt "pass" :bcrypt+sha512 {:iterations 10}) ``` ```clojure ; Production (balanced) (hashers/encrypt "pass" :bcrypt+sha512 {:iterations 12}) ``` ```clojure ; High-security (hashers/encrypt "pass" :scrypt+sha512 {:cpu 32 :mem 2}) ``` -------------------------------- ### Secure vs. Insecure Logging Source: https://github.com/funcool/buddy/blob/master/_autodocs/security-best-practices.md Illustrates secure logging practices by avoiding the exposure of sensitive data like passwords. The 'good' example logs only necessary information, while the 'bad' example leaks sensitive credentials. ```clojure ; Good - doesn't leak password (log/info "Login attempt" :username username) ; Bad - exposes password (log/debug "Authenticating with:" :username username :password password) ``` -------------------------------- ### HTTP Basic Auth Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md Configure HTTP Basic Authentication for your application. This example sets up a backend that authorizes requests based on provided username and password credentials. ```clojure (require '[buddy.auth.backends.httpbasic :as httpbasic]) (def backend (httpbasic/http-basic-backend {:authorizefn (fn [request username password] (let [user (check-credentials username password)] (when user {:username username})))})) (def app (-> handler (auth-middleware/wrap-authentication backend))) ``` -------------------------------- ### Login with Session Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md Implement session-based authentication for user logins. This example uses the session backend and Ring's wrap-session middleware to manage user sessions after successful authentication. ```clojure (require '[buddy.auth.backends.session :as session]) (require '[ring.middleware.session :refer [wrap-session]]) (def backend (session/session-backend)) (def login-handler (POST "/login" request (let [{:keys [username password]} (:form-params request) user (authenticate-user username password)] (if user {:status 302 :headers {"Location" "/dashboard"} :session {:identity user}} {:status 401 :body "Invalid credentials"}))))) (def app (-> handler (wrap-session) (auth-middleware/wrap-authentication backend))) ``` -------------------------------- ### JWT Header Example Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Example of a JWT header, specifying the algorithm and token type. ```json { "alg":"HS256", "typ":"JWT" } ``` -------------------------------- ### Unsign Token with RSA Algorithm Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Use RSA algorithms for verification when the verifier only has the public key. This example demonstrates unsigning a token using the PS256 algorithm. ```clojure (def pub-key (load-public-key "public.pem")) (jws/unsign token pub-key :ps256) ``` -------------------------------- ### Recommended Environment Variables for Buddy Source: https://github.com/funcool/buddy/blob/master/_autodocs/quick-reference.md Lists essential environment variables for configuring JWT, password hashing, and encryption settings within a Buddy project. These variables should be set in the environment before the application starts. ```bash # JWT and Signing JWT_SECRET= JWT_ALGORITHM=hs256 JWT_EXPIRATION=3600 # Password Hashing BCRYPT_ITERATIONS=12 PASSWORD_ALGORITHM=bcrypt+sha512 # Encryption ENCRYPTION_KEY= ENCRYPTION_ALGORITHM=aes # Key Paths PRIVATE_KEY_PATH=/path/to/private.pem PUBLIC_KEY_PATH=/path/to/public.pem ``` -------------------------------- ### Implement Rate Limiting with Token Claims Source: https://github.com/funcool/buddy/blob/master/_autodocs/integration-patterns.md Control request frequency using token claims and a sliding window. This example tracks requests per client per second. ```clojure (ns myapp.rate-limit (:require [buddy.sign.jws :as jws])) (def rate-limits (atom {})) (defn increment-request-count [client-id] (let [now (System/currentTimeMillis) window (quot now 1000) ; 1-second window] (swap! rate-limits (fn [limits] (update-in limits [client-id window] (fnil inc 0)))))) (defn check-rate-limit [client-id limit] (let [now (System/currentTimeMillis) window (quot now 1000) count (get-in @rate-limits [client-id window] 0)] (< count limit))) (defn wrap-rate-limit [handler {:keys [requests-per-second]}] (fn [request] (let [user (:user request) client-id (or (:client-id user) (:sub user))] (if (check-rate-limit client-id requests-per-second) (do (increment-request-count client-id) (handler request)) {:status 429 :body {:error "Rate limit exceeded"} :headers {"Retry-After" "1"}})))) ``` -------------------------------- ### Get Supported Signing Algorithms Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Retrieve a map of supported signing algorithm keywords and their corresponding string names. This can be used to dynamically determine available signing methods. ```clojure (jws/sign-alg) ; => {:hs256 "HS256" :hs384 "HS384" :hs512 "HS512" :rs256 "RS256" ...} ``` -------------------------------- ### JWT Unsign with Leeway for Clock Skew Source: https://github.com/funcool/buddy/blob/master/_autodocs/error-handling.md This example demonstrates how to use the `:leeway` option with `jws/unsign` to allow for clock skew tolerance during token expiration checks. ```clojure (jws/unsign token secret :hs256 {:leeway 30}) ; 30-second tolerance ``` -------------------------------- ### Sign Token with RSA Algorithm Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Use RSA algorithms when the verifier only has the public key, suitable for multiple independent verifiers or external consumption. This example uses the PS256 algorithm. ```clojure (def priv-key (load-private-key "private.pem")) (jws/sign claims priv-key :ps256) ``` -------------------------------- ### Handling Token Backend Exceptions in Clojure Source: https://github.com/funcool/buddy/blob/master/_autodocs/error-handling.md Provides an example of a token backend configuration in Clojure that includes error handling for token parsing and validation. The `:authorizefn` catches exceptions during token validation and logs them, returning nil to indicate failure. ```clojure (def backend (token-backend/token-backend {:token-name "Authorization" :authorizefn (fn [request token] (try (validate-token token) (catch Exception e (do (log/warn "Token validation failed" e) nil))))})) ``` -------------------------------- ### Protected Route with Token Auth Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md Implement token-based authentication for protected routes. This example uses a custom token name and defines an authorization function to validate tokens and extract user information. ```clojure (require '[buddy.auth.backends.token :as token-backend]) (require '[buddy.auth.middleware :as auth-middleware]) (def backend (token-backend/token-backend {:token-name "X-Auth-Token" :authorizefn (fn [request token] (when (valid-token? token) {:user-id (get-user-from-token token)}))})) (def handler (GET "/api/users" request (if (auth/authenticated? request) {:status 200 :body (get-user-info (:identity request))} {:status 401 :body "Unauthorized"}))) (def app (-> handler (auth-middleware/wrap-authentication backend))) ``` -------------------------------- ### Clojure Cryptographic Algorithm Selection for Performance Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Provides examples of selecting faster cryptographic algorithms for performance-sensitive applications, such as :hs256 for symmetric signing and :chacha for stream ciphers. ```clojure ; Faster symmetric signing :hs256 ; vs :ps256 which is slower ; Faster stream cipher :chacha ; vs :aes-256 ``` -------------------------------- ### Sign Token with Elliptic Curve Algorithm Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Use Elliptic Curve algorithms when signature size is a concern or modern cryptography and performance are critical. This example uses the ES256 algorithm. ```clojure (def priv-key (load-private-key "ec-private.pem")) (jws/sign claims priv-key :es256) ``` -------------------------------- ### Avoid Storing Plaintext Passwords Source: https://github.com/funcool/buddy/blob/master/_autodocs/security-best-practices.md This example shows an incorrect way to store passwords, highlighting the danger of not hashing them. Never store passwords in their original, readable format. ```clojure ; WRONG - Never do this (db/insert :users {:username username :password plaintext-password}) ``` -------------------------------- ### Buddy Core API Source: https://github.com/funcool/buddy/blob/master/_autodocs/MANIFEST.txt Documentation for core cryptographic functions including hash functions, key management, digital signatures, MAC functions, block and stream ciphers, key derivation functions, and random number generation. It details over 45 functions with signatures, parameters, and examples. ```APIDOC ## Buddy Core API Reference ### Description Provides access to fundamental cryptographic operations. ### Functions - **Hash Functions**: digest, SHA-256, SHA-512 - **Key Management**: public/private keys - **Digital Signatures**: ECDSA, RSA - **MAC Functions**: HMAC, Poly1305 - **Block Ciphers**: AES, Twofish - **Stream Ciphers**: ChaCha20 - **Key Derivation Functions**: PBKDF2, scrypt - **Random Number Generation**: Various methods ### Details Over 45 functions are documented with complete API signatures, parameter tables, and real-world code examples. ``` -------------------------------- ### Role-Based Access Control Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md Set up role-based access control (RBAC) to restrict access to routes based on user roles. This example defines rules for admin-specific routes and general API routes. ```clojure (require '[buddy.auth.accessrules :as acl]) (def rules [{:pattern #"^/admin/.*" :rule (fn [request] (let [user (:identity request)] (some? (#{:admin} (:role user)))))} {:pattern #"^/api/.*" :rule (fn [request] (acl/authenticated? request))}]) (def app (-> handler (auth-middleware/wrap-authorization rules) (auth-middleware/wrap-authorization-exception))) ``` -------------------------------- ### Unsign JWT and Handle Errors Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Verify and decode a JWT using the provided secret key and algorithm. This example demonstrates how to catch potential errors like invalid signatures or expired tokens. ```clojure (try (def claims (jws/unsign token "secret-key")) (println "User ID:" (:user-id claims)) (catch buddy.sign.util.BadSignatureError e (println "Token signature invalid")) (catch buddy.sign.util.TokenExpiredError e (println "Token has expired"))) ``` -------------------------------- ### Authenticate Request with Token Backend Source: https://github.com/funcool/buddy/blob/master/_autodocs/quick-reference.md Set up a token-based authentication backend and wrap your application handler with `buddy.auth.middleware/wrap-authentication`. ```clojure (require '[buddy.auth.backends.token :as token-backend]) (require '[buddy.auth.middleware :as auth-mw]) (def backend (token-backend/token-backend {:token-name "Authorization" :authorizefn (fn [r token] (jws/unsign token "secret"))})) (def app (-> handler (auth-mw/wrap-authentication backend))) ``` -------------------------------- ### JWT Payload Example Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Example of a JWT payload containing claims such as subject, username, and expiration time. ```json { "sub":"user123", "username":"john", "exp":1234567890 } ``` -------------------------------- ### Sign JWT with Expiration Source: https://github.com/funcool/buddy/blob/master/_autodocs/security-best-practices.md Always set an expiration time for JWTs to limit their validity period. This example sets a 1-hour expiration. ```clojure (let [now (quot (System/currentTimeMillis) 1000) token (jws/sign {:sub user-id :iat now :exp (+ now 3600)} ; 1 hour secret)] token) ``` -------------------------------- ### HTTP Basic Backend Configuration Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md Set up an HTTP Basic Authentication backend. Provide a function to validate the username and password credentials. ```clojure (require '[buddy.auth.backends.httpbasic :as httpbasic]) (def backend (httpbasic/http-basic-backend {:authorizefn (fn [request username password] (if (= [username password] ["admin" "secret"]) {:user username} nil))})) ``` -------------------------------- ### Implement JWT Revocation Source: https://github.com/funcool/buddy/blob/master/_autodocs/security-best-practices.md Implement a mechanism to revoke tokens, such as maintaining a blacklist of token identifiers (jti). This example shows logout and validation functions. ```clojure (def blacklist (atom #{})) (defn logout [token] (if-let [claims (try (jws/unsign token secret) (catch Exception _ nil))] (swap! blacklist conj (:jti claims)))) (defn is-valid-token? [token] (if-let [claims (try (jws/unsign token secret) (catch Exception _ nil))] (not (contains? @blacklist (:jti claims))) false)) ``` -------------------------------- ### Clojure REPL Interaction with Buddy Modules Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Demonstrates how to load and interact with Buddy's hash, hashers, and jws modules within a Clojure REPL. ```clojure (require '[buddy.core.hash :as hash]) (require '[buddy.hashers :as hashers]) (require '[buddy.sign.jws :as jws]) ; Test hash (hash/digest :sha256 "hello") ; Test password (def h (hashers/encrypt "password")) (hashers/check "password" h) ; Test JWT (def token (jws/sign {:id 1} "secret")) (jws/unsign token "secret") ``` -------------------------------- ### Generate and Verify API Keys with Buddy Source: https://github.com/funcool/buddy/blob/master/_autodocs/integration-patterns.md Implement a token-based API key system. This involves generating keys, storing their hashes, and verifying incoming requests. ```clojure (ns myapp.apikey (:require [buddy.core.hash :as hash] [buddy.core.nonce :as nonce])) (defn generate-api-key [] (let [key (nonce/random-str 32)] {:public-key key :secret-hash (hash/digest :sha256 key :hex)})) (defn store-api-key [client-id {:keys [public-key secret-hash]}] (db/insert :api-keys {:client-id client-id :public-key public-key :secret-hash secret-hash :created-at (System/currentTimeMillis)})) (defn verify-api-key [public-key secret-key] (if-let [key-record (db/query :api-keys {:public-key public-key})]) (let [provided-hash (hash/digest :sha256 secret-key :hex)] (if (hash/is-same? provided-hash (:secret-hash key-record)) {:valid true :client-id (:client-id key-record)} {:valid false})) {:valid false})) (defn wrap-api-key-auth [handler] (fn [request] (if-let [api-key (get-in request [:headers "x-api-key"])] (let [[public secret] (clojure.string/split api-key #":")] (if-let [{:keys [valid client-id]} (verify-api-key public secret)] (handler (assoc request :client-id client-id)) {:status 401 :body {:error "Invalid API key"}})) (handler request)))) ``` -------------------------------- ### Migrate from Session to JWT Authentication Source: https://github.com/funcool/buddy/blob/master/_autodocs/quick-reference.md Demonstrates the transition from session-based authentication to JWT-based authentication using Buddy. The old code uses `wrap-session`, while the new code configures a `token-backend` and uses `wrap-authentication`. ```clojure ; Old: session-based (wrap-session) ``` ```clojure ; New: JWT in header (def backend (token-backend/token-backend {...})) (wrap-authentication handler backend) ``` -------------------------------- ### Sign Token with HMAC Algorithm Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Use HMAC algorithms when the issuer and verifier are the same system and the secret key can be kept confidential. This example uses the HS256 algorithm. ```clojure (jws/sign claims "shared-secret-key" :hs256) ``` -------------------------------- ### Token Backend Configuration Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md Configure a token-based authentication backend. Specify the header/parameter name for the token and a function to validate it. ```clojure (require '[buddy.auth.backends.token :as token-backend]) (def backend (token-backend/token-backend {:token-name "Authorization" :authorizefn (fn [request token] (if (valid-token? token) {:user-id (extract-user-id token)} nil))})) ``` -------------------------------- ### Add Buddy Auth, Sign, and Hashers for Web Apps Source: https://github.com/funcool/buddy/blob/master/_autodocs/modules-overview.md Use these dependencies for Ring-based web applications requiring user authentication, token signing, and password hashing. ```clojure [buddy/buddy-auth "2.1.0"] [buddy/buddy-sign "2.2.0"] [buddy/buddy-hashers "1.3.0"] ``` -------------------------------- ### Sign and Verify Messages Source: https://github.com/funcool/buddy/blob/master/_autodocs/quick-reference.md Use `buddy.core.sign` for message signing and verification. Requires private and public keys. ```clojure (require '[buddy.core.sign :as sign]) (require '[buddy.core.keys :as keys]) (def priv (keys/private-key "private.pem")) (def pub (keys/public-key "public.pem")) (def sig (sign/sign "message" priv :ecdsa)) (sign/verify "message" sig pub :ecdsa) ``` -------------------------------- ### Validate JWT Claims Source: https://github.com/funcool/buddy/blob/master/_autodocs/security-best-practices.md When unsigning a JWT, validate critical claims like expiration and algorithm. This example uses a 30-second leeway and enforces strict algorithm checking. ```clojure (jws/unsign token secret :hs256 {:leeway 30 :strict-alg-check? true}) ``` -------------------------------- ### Create and Verify JWT Tokens Source: https://github.com/funcool/buddy/blob/master/_autodocs/integration-patterns.md This snippet demonstrates creating access and refresh tokens with expiration and unique IDs, and verifying token validity. It requires the buddy.sign.jws and buddy.core.nonce libraries. ```clojure (ns myapp.api.auth (:require [buddy.sign.jws :as jws] [buddy.core.nonce :as nonce] [clj-time.core :as time])) (def jwt-secret (System/getenv "JWT_SECRET")) (def token-ttl 3600) ; 1 hour (defn create-access-token [user-id username roles] (let [now (quot (System/currentTimeMillis) 1000) claims {:sub user-id :username username :roles roles :iat now :exp (+ now token-ttl) :jti (nonce/random-str 16)}] (jws/sign claims jwt-secret :hs256))) (defn create-refresh-token [user-id] (let [now (quot (System/currentTimeMillis) 1000) refresh-ttl (* 7 24 60 60) ; 7 days claims {:sub user-id :type :refresh :iat now :exp (+ now refresh-ttl) :jti (nonce/random-str 16)}] (jws/sign claims jwt-secret :hs256))) (defn verify-token [token] (try (jws/unsign token jwt-secret :hs256) (catch Exception e nil))) (defn refresh-access-token [refresh-token] (if-let [claims (verify-token refresh-token)] (if (= :refresh (:type claims)) (create-access-token (:sub claims) nil (:roles claims)) nil) nil)) ; Integration with Ring (defn wrap-jwt-auth [handler] (fn [request] (if-let [auth-header (get-in request [:headers "authorization"])] (if-let [token (second (clojure.string/split auth-header #" "))] (if-let [claims (verify-token token)] (handler (assoc request :user claims)) {:status 401 :body {:error "Invalid token"}}) {:status 401 :body {:error "Missing token"}}) (handler request)))) ``` -------------------------------- ### HTTP Basic Authentication Backend Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Configure an HTTP Basic Authentication backend using buddy.hashers and buddy.auth.backends.httpbasic. This involves defining an authorize function that checks user credentials against hashed passwords. ```clojure (require '[buddy.hashers :as hashers] '[buddy.auth.backends.httpbasic :as httpbasic]) (def backend (httpbasic/http-basic-backend {:authorizefn (fn [request username password] (let [user (find-user username)] (when (hashers/check password (:hash user)) {:username username :id (:id user)})))} )) (def app (-> handler (auth-middleware/wrap-authentication backend))) ``` -------------------------------- ### Buddy Auth Token Backend Configuration Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Sets up a token backend for buddy-auth, specifying the token name and an authorization function. The authorization function verifies a JWT token, extracts claims, and returns user details or nil on failure. ```clojure (require '[buddy.auth.backends.token :as token-backend]) (require '[buddy.sign.jws :as jws]) (def backend (token-backend/token-backend {:token-name "Authorization" :authorizefn (fn [request token] (try (let [claims (jws/unsign token "secret" :hs256 {:leeway 30})] {:user-id (:sub claims) :username (:username claims)}) (catch Exception e nil)))}) ``` -------------------------------- ### Load Public Key from PEM File Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-core-api.md Loads a public key from a file path. Assumes the key is in PEM format by default. Requires the `buddy.core.keys` namespace. ```clojure (require '[buddy.core.keys :as keys]) ; Load from PEM file (def pub-key (keys/public-key "path/to/public.pem")) ``` -------------------------------- ### Session Backend Initialization Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md Initialize a session-based authentication backend. This backend relies on Ring sessions to manage user identity. ```clojure (require '[buddy.auth.backends.session :as session]) (def backend (session/session-backend)) (def app (-> handler (wrap-session) (auth-middleware/wrap-authentication backend))) ``` -------------------------------- ### JWT Authentication Backend Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Set up a JWT authentication backend using buddy.sign.jws and buddy.auth.backends.token. Requires a JWT secret key for signing and unsigning tokens. ```clojure (require '[buddy.sign.jws :as jws] '[buddy.auth.backends.token :as token-backend]) (def jwt-secret "my-secret-key") (def backend (token-backend/token-backend {:token-name "Authorization" :authorizefn (fn [request token] (try (jws/unsign token jwt-secret :hs256) (catch Exception _ nil)))}) ) ``` -------------------------------- ### Configure Logback for Buddy Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Add this XML configuration to resources/logback.xml to set up console logging for the Buddy application. It enables DEBUG level logging for the 'buddy' logger and INFO level for the root logger. ```xml %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n ``` -------------------------------- ### Get Authenticated User Identity Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md Retrieve the authenticated user's identity from the request map using the `identity` function. This is useful for accessing user-specific data after successful authentication. ```clojure (let [user (auth/identity request)] (println "Username:" (:username user))) ``` -------------------------------- ### Generate and Verify HMAC Source: https://github.com/funcool/buddy/blob/master/_autodocs/quick-reference.md Use `buddy.core.mac/hmac` to generate an HMAC and `buddy.core.mac/verify-hmac` to verify it. ```clojure (require '[buddy.core.mac :as mac]) (mac/hmac "message" "secret-key" :hmac+sha256) (mac/verify-hmac computed-hmac provided-hmac) ``` -------------------------------- ### Create Digital Signature with Buddy Core Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-core-api.md Use this function to create a digital signature for given data using a private key and an optional algorithm. Ensure the private key is loaded correctly. ```clojure (require '[buddy.core.sign :as sign]) (require '[buddy.core.keys :as keys]) (def priv-key (keys/private-key "private.pem")) (def signature (sign/sign "message" priv-key :ecdsa)) ``` -------------------------------- ### Buddy Hashers API Source: https://github.com/funcool/buddy/blob/master/_autodocs/MANIFEST.txt Documentation for password encryption and verification functions, including bcrypt, PBKDF2, and scrypt. It details algorithm detection, selection, and hash update checking, with 6 core functions and detailed examples. ```APIDOC ## Buddy Hashers API Reference ### Description Provides functions for secure password hashing and verification. ### Functions - **Password Encryption**: bcrypt, PBKDF2, scrypt - **Password Verification**: Timing-attack resistant verification - **Algorithm Detection and Selection** - **Hash Update Checking** ### Details Includes 6 core functions with detailed examples and security considerations. ``` -------------------------------- ### Ring Middleware with Buddy Authentication Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Configure a basic Ring application with Buddy's authentication and authorization middleware, including access rules. ```clojure (ns myapp.core (:require [ring.adapter.jetty :refer [run-jetty]] [ring.middleware.session :refer [wrap-session]] [ring.middleware.params :refer [wrap-params]] [buddy.auth.middleware :as auth-middleware] [buddy.auth.backends.token :as token-backend] [buddy.auth.accessrules :as acl])) (def auth-backend (token-backend/token-backend {:token-name "Authorization" :authorizefn validate-token})) (def access-rules [{:pattern #"^/admin/.*" :rule (fn [request] (some-> request :identity :admin true?))} {:pattern #"^/api/.*" :rule :authenticated}]) (defn handler [request] {:status 200 :body "OK"}) (def app (-> handler (auth-middleware/wrap-authorization access-rules) (auth-middleware/wrap-authentication auth-backend) (auth-middleware/wrap-authorization-exception) wrap-params wrap-session)) (defn -main [] (run-jetty app {:port 3000})) ``` -------------------------------- ### Buddy Sign API Source: https://github.com/funcool/buddy/blob/master/_autodocs/MANIFEST.txt Reference for JSON Web Signature (JWS) and JSON Web Encryption (JWE) operations, including compact message format, signing algorithms, and token claims validation. It covers over 8 core functions with examples. ```APIDOC ## Buddy Sign API Reference ### Description Enables operations related to JSON Web Signatures (JWS) and JSON Web Encryption (JWE). ### Features - JSON Web Signature (JWS) operations - JSON Web Encryption (JWE) - Compact message format - Signing algorithms reference - Token claims and validation ### Details Documents over 8 core functions with practical examples. ``` -------------------------------- ### Migrate from Custom Signing to buddy-sign Source: https://github.com/funcool/buddy/blob/master/_autodocs/quick-reference.md Shows how to replace a custom HMAC implementation with Buddy's `buddy-sign` library for signing data. The old code uses a custom function, while the new code utilizes `jws/sign` with a specified algorithm. ```clojure ; Old: custom HMAC implementation (my-custom-sign-fn data secret) ``` ```clojure ; New: use buddy-sign (jws/sign data secret :hs256) ``` -------------------------------- ### Integration with buddy-auth Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Configures a token authentication backend for buddy-auth, specifying how to extract and verify tokens. ```APIDOC ## Integration with buddy-auth ### Description Configures a token authentication backend for buddy-auth, specifying how to extract and verify tokens. ### Backend Configuration - `:token-name` (string) - The name of the header or parameter containing the token (e.g., "Authorization"). - `:authorizefn` (function) - A function that takes the request and the token, and returns user credentials if valid, or `nil` otherwise. ### Token Verification Details within `authorizefn`: - **Secret Key**: "secret" (hardcoded in example, should be managed securely) - **Algorithm**: HS256 - **Leeway**: 30 seconds for expiration validation. ### Example ```clojure (require '[buddy.auth.backends.token :as token-backend]) (require '[buddy.sign.jws :as jws]) (def backend (token-backend/token-backend {:token-name "Authorization" :authorizefn (fn [request token] (try (let [claims (jws/unsign token "secret" :hs256 {:leeway 30})] {:user-id (:sub claims) :username (:username claims)}) (catch Exception e nil)))}) ``` ``` -------------------------------- ### buddy.core.keys/public-key Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-core-api.md Loads a public key from various data formats including PEM, DER, and PKCS8. ```APIDOC ## buddy.core.keys/public-key ### Description Load a public key from various formats. ### Signature ```clojure (public-key data) (public-key data format) ``` ### Parameters #### Path Parameters - **data** (string, bytes, or file) - Required - Key data or path - **format** (keyword) - Optional - Format (`:pem`, `:der`, `:pkcs8`) ### Returns `java.security.PublicKey` object ### Throws Various key parsing exceptions ### Example ```clojure (require '[buddy.core.keys :as keys]) ; Load from PEM file (def pub-key (keys/public-key "path/to/public.pem")) ; Load from string (def pub-key (keys/public-key "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----")) ``` ``` -------------------------------- ### Middleware Composition for Authentication and Authorization Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md A typical middleware stack order for handling authentication and authorization using Buddy. Ensure authorization rules are checked after authentication. ```clojure (-> handler (auth-middleware/wrap-authorization rules) ; Check rules after auth (auth-middleware/wrap-authentication backend) ; Perform authentication (auth-middleware/wrap-authorization-exception) ; Catch exceptions (wrap-session)) ; Session support ``` -------------------------------- ### Buddy Auth HTTP Basic Backend Integration Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-hashers-api.md Shows how to integrate Buddy Hashers with buddy-auth's HTTP Basic authentication backend. It includes a function to find a user and check their password against the stored hash. ```clojure (require '[buddy.hashers :as hashers]) (require '[buddy.auth.backends.httpbasic :as httpbasic]) (def backend (httpbasic/http-basic-backend {:authorizefn (fn [request username password] (let [user (find-user username) hash (:password-hash user)] (when (hashers/check password hash) {:username username :user-id (:id user)})))}) ``` -------------------------------- ### Add Buddy Meta-Package Dependency Source: https://github.com/funcool/buddy/blob/master/_autodocs/README.md Add the Buddy meta-package to your project.clj file for a consolidated dependency. ```clojure [buddy "2.0.0"] ``` -------------------------------- ### Add Individual Buddy Module Dependencies Source: https://github.com/funcool/buddy/blob/master/_autodocs/README.md Add individual Buddy modules to your project.clj file for selective inclusion. ```clojure [buddy/buddy-core "1.4.0"] [buddy/buddy-auth "2.1.0"] [buddy/buddy-hashers "1.3.0"] [buddy/buddy-sign "2.2.0"] ``` -------------------------------- ### Hash Data with Buddy Source: https://github.com/funcool/buddy/blob/master/_autodocs/quick-reference.md Use `buddy.core.hash/digest` to hash data. Specify the output format as :hex, :base64, or :bytes. ```clojure (require '[buddy.core.hash :as hash]) (hash/digest :sha256 "data") ; hex string (hash/digest :sha256 "data" :base64) ; base64 (hash/digest :sha256 "data" :bytes) ; byte array ``` -------------------------------- ### Check Java Version Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Verify that your Java Development Kit (JDK) version is 7 or later to ensure compatibility. ```bash java -version ``` -------------------------------- ### Encrypt with Bcrypt Options Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-hashers-api.md Encrypts a password using bcrypt+sha512 with a specified number of iterations. Higher iterations increase security but also computation time. ```clojure (hashers/encrypt "pass" :bcrypt+sha512 {:iterations 14}) ``` -------------------------------- ### Encrypt and Decrypt Data Source: https://github.com/funcool/buddy/blob/master/_autodocs/quick-reference.md Use `buddy.core.crypto` for encryption and decryption. Requires a key and an initialization vector (IV). ```clojure (require '[buddy.core.crypto :as crypto]) (require '[buddy.core.nonce :as nonce]) (def key (nonce/random-bytes 32)) (def iv (nonce/random-bytes 16)) (crypto/encrypt "plaintext" key :aes {:mode :cbc :iv iv}) (crypto/decrypt ciphertext key :aes {:mode :cbc :iv iv}) ``` -------------------------------- ### Clojure Cryptographic Algorithm Selection for Security Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Illustrates choosing more secure cryptographic algorithms for high-security applications, recommending :ps256 over :hs256 and :scrypt over :pbkdf2. ```clojure ; More resistant to attacks :ps256 ; instead of :hs256 :scrypt ; instead of :pbkdf2 ``` -------------------------------- ### Application Configuration Namespace Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Define application-wide configuration options including JWT, token authentication, password hashing, and encryption settings. ```clojure (ns myapp.config (:require [buddy.core.keys :as keys])) (def jwt-options {:algorithm :hs256 :secret (System/getenv "JWT_SECRET")}) (def token-auth-options {:token-name "Authorization" :authorizefn validate-token}) (def password-hash-options {:algorithm :bcrypt+sha512 :iterations 12}) (def encryption-options {:algorithm :aes :mode :cbc :key-size 256}) ``` -------------------------------- ### buddy.core.keys/private-key Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-core-api.md Loads a private key from various data formats, supporting encrypted keys with a password. ```APIDOC ## buddy.core.keys/private-key ### Description Load a private key from various formats. ### Signature ```clojure (private-key data) (private-key data password) ``` ### Parameters #### Path Parameters - **data** (string, bytes, or file) - Required - Key data or path - **password** (string or bytes) - Optional - Passphrase for encrypted keys ### Returns `java.security.PrivateKey` object ### Example ```clojure ; Load encrypted private key (def priv-key (keys/private-key "path/to/private.pem" "passphrase")) ``` ``` -------------------------------- ### Recommended Signing Algorithms Source: https://github.com/funcool/buddy/blob/master/_autodocs/security-best-practices.md Use recommended signing algorithms like HS256, PSS (PS256), and ECDSA (ES256). Avoid deprecated algorithms like SHA-1 (HS1) and RSA PKCS#1 v1.5 (RS256). ```clojure ; Recommended (jws/sign claims secret :hs256) (jws/sign claims priv-key :ps256) ; RSA with PSS (jws/sign claims priv-key :es256) ; ECDSA ; Avoid (jws/sign claims secret :hs1) ; SHA-1 (jws/sign claims priv-key :rs256) ; RSA PKCS#1 v1.5 ``` -------------------------------- ### Upgrade Leiningen Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Upgrade your Leiningen build tool to resolve 'Could not find artifact' errors. ```bash lein upgrade ``` -------------------------------- ### Session-Based Auth with Password Hashing Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Implement session-based authentication using buddy.hashers and buddy.auth.backends.session. This pattern includes password hashing and checking for secure login handling. ```clojure (require '[buddy.hashers :as hashers] '[buddy.auth.backends.session :as session-backend] '[ring.middleware.session :refer [wrap-session]]) (def backend (session-backend/session-backend)) (defn login-handler [request] (let [{:keys [username password]} (:form-params request) user (find-user username) hash (:password-hash user)] (if (hashers/check password hash) {:status 302 :headers {"Location" "/dashboard"} :session {:identity user}} {:status 401 :body "Invalid credentials"}))) (def app (-> handler wrap-session (auth-middleware/wrap-authentication backend))) ``` -------------------------------- ### Configure Java Target and Source Version Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Set the Java target and source versions to 1.7 in your project.clj file for Java 7 compatibility. ```clojure :java-source-paths ["src"] :javac-options ["-target" "1.7" "-source" "1.7"] ``` -------------------------------- ### Generate Leiningen POM File Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Generate a project.clm file using Leiningen, which can help resolve artifact issues. ```bash lein pom ``` -------------------------------- ### HTTP Basic Backend Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md Implements HTTP Basic Authentication as defined by RFC 7617, requiring username and password for authentication. ```APIDOC ## http-basic-backend ### Description Implements HTTP Basic Authentication (RFC 7617). ### Signature ```clojure (http-basic-backend options) ``` ### Parameters #### Options - **`:authorizefn`** (function) - Required - Function to validate credentials `(fn [request username password] ...)`. ### Returns Authentication backend object ### Example ```clojure (require '[buddy.auth.backends.httpbasic :as httpbasic]) (def backend (httpbasic/http-basic-backend {:authorizefn (fn [request username password] (if (= [username password] ["admin" "secret"]) {:user username} nil))})) ``` ``` -------------------------------- ### Sign Binary Data with Buddy Compact Format Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Creates a signed message using the compact format. Accepts binary data, a secret key, and an optional signing algorithm. The default algorithm is :hs256. ```clojure (require '[buddy.sign.compact :as compact]) (def message (compact/sign (.getBytes "binary data") "secret")) ``` -------------------------------- ### Token Backend Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-auth-api.md Implements token-based authentication, allowing for stateless authentication using tokens provided in headers or URL parameters. ```APIDOC ## token-backend ### Description Implements token-based authentication (stateless). ### Signature ```clojure (token-backend options) ``` ### Parameters #### Options - **`:token-name`** (string) - Optional - Header name or parameter name. Defaults to `"Authorization"`. - **`:authorizefn`** (function) - Required - Function to validate token `(fn [request token] ...)`. ### Token Resolution - From `Authorization` header: `Authorization: Token ` - From custom header specified in `:token-name` - From URL parameter specified in `:token-name` (with `?` prefix) ### Example ```clojure (require '[buddy.auth.backends.token :as token-backend]) (def backend (token-backend/token-backend {:token-name "Authorization" :authorizefn (fn [request token] (if (valid-token? token) {:user-id (extract-user-id token)} nil))})) ``` ``` -------------------------------- ### Create and Unsign JWT Source: https://github.com/funcool/buddy/blob/master/_autodocs/quick-reference.md Use `buddy.sign.jws` to create (sign) and unsign JSON Web Tokens (JWTs). ```clojure (require '[buddy.sign.jws :as jws]) (def token (jws/sign {:user-id 123} "secret" :hs256)) (def claims (jws/unsign token "secret" :hs256)) ``` -------------------------------- ### buddy.sign.jws/sign-alg Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-sign-api.md Retrieves a map of supported algorithm keywords and their corresponding names. ```APIDOC ## buddy.sign.jws/sign-alg ### Description Get algorithm keyword for given algorithm name. ### Signature ```clojure (sign-alg) ``` ### Returns Map of algorithm keywords and names ### Example ```clojure (jws/sign-alg) ; => {:hs256 "HS256" :hs384 "HS384" :hs512 "HS512" :rs256 "RS256" ...} ``` ``` -------------------------------- ### Encrypt with PBKDF2 Options Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-hashers-api.md Encrypts a password using pbkdf2+sha256 with a custom iteration count. The default is 100000, which offers a good balance of security and performance. ```clojure (hashers/encrypt "pass" :pbkdf2+sha256 {:iterations 100000}) ``` -------------------------------- ### Load Encrypted Private Key Source: https://github.com/funcool/buddy/blob/master/_autodocs/buddy-core-api.md Loads an encrypted private key from a file path, requiring a passphrase for decryption. Requires the `buddy.core.keys` namespace. ```clojure (def priv-key (keys/private-key "path/to/private.pem" "passphrase")) ``` -------------------------------- ### Configure Java Target and Source in project.clj Source: https://github.com/funcool/buddy/blob/master/_autodocs/installation-guide.md Set the target and source versions for Java compilation in your project.clj file. ```clojure :target-path "target/%s" :javac-options ["-target" "1.8" "-source" "1.8"] ```