### Create a Macaroon with First-Party Caveat Source: https://github.com/ecordell/pymacaroons/blob/master/README.md Use this to construct a new macaroon, add a first-party caveat specifying an authorization requirement, and then serialize it for transport. Ensure you have the correct signing key associated with the identifier. ```python from pymacaroons import Macaroon, Verifier keys = { 'key-for-bob': 'asdfasdfas-a-very-secret-signing-key' } m = Macaroon( location='cool-picture-service.example.com', identifier='key-for-bob', key=keys['key-for-bob'] ) m.add_first_party_caveat('picture_id = bobs_cool_cat.jpg') print(m.inspect()) serialized = m.serialize() print(serialized) ``` -------------------------------- ### Verify Third-Party Caveats Source: https://context7.com/ecordell/pymacaroons/llms.txt Use prepare_for_request() to bind discharge macaroons to a root macaroon before verification. ```python from pymacaroons import Macaroon, Verifier # Step 1: Target service creates macaroon with third-party caveat root_key = 'this is a different super-secret key; never use the same secret twice' m = Macaroon( location='http://mybank/', identifier='we used our other secret key', key=root_key ) m.add_first_party_caveat('account = 3735928559') # Third-party caveat requires auth service verification caveat_key = '4; guaranteed random by a fair toss of the dice' caveat_id = 'this was how we remind auth of key/pred' m.add_third_party_caveat('http://auth.mybank/', caveat_key, caveat_id) # Step 2: Client obtains discharge macaroon from third-party service discharge = Macaroon( location='http://auth.mybank/', key=caveat_key, identifier=caveat_id ) discharge.add_first_party_caveat('time < 2025-01-01T00:00') # Step 3: Bind discharge to root macaroon (prevents reuse with other macaroons) protected_discharge = m.prepare_for_request(discharge) # Step 4: Target service verifies the macaroon chain v = Verifier(discharge_macaroons=[protected_discharge]) v.satisfy_exact('account = 3735928559') v.satisfy_exact('time < 2025-01-01T00:00') verified = v.verify(m, root_key) print(f"Verified: {verified}") # Output: Verified: True ``` -------------------------------- ### Initialize a Macaroon Source: https://context7.com/ecordell/pymacaroons/llms.txt Create a new Macaroon instance by specifying the location, identifier, and secret key. Supports both V1 and V2 formats. ```python from pymacaroons import Macaroon, MACAROON_V1, MACAROON_V2 # Create a basic macaroon (V1 format by default) m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) print(m.signature) # Output: e3d9e02908526c4c0039ae15114115d97fdd68bf2ba379b342aaf0f617d0552f # Create a V2 format macaroon (more compact binary format) m_v2 = Macaroon( location='http://mybank/', identifier='key-v2', key='secret-key-v2', version=MACAROON_V2 ) # Macaroon properties print(m.location) # 'http://mybank/' print(m.identifier) # 'we used our secret key' print(m.version) # 1 (MACAROON_V1) ``` -------------------------------- ### Add First-Party Caveats Source: https://context7.com/ecordell/pymacaroons/llms.txt Embed predicates into a Macaroon that are verified directly by the target service. ```python from pymacaroons import Macaroon m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) # Add caveats to restrict the macaroon's use m.add_first_party_caveat('account = 3735928559') m.add_first_party_caveat('time < 2025-01-01T00:00') m.add_first_party_caveat('operation = withdraw') m.add_first_party_caveat('amount < 100') # Each caveat changes the signature print(m.signature) # Output: (new signature incorporating all caveats) # Retrieve first-party caveats for caveat in m.first_party_caveats(): print(f"Caveat ID: {caveat.caveat_id}") # Output: # Caveat ID: account = 3735928559 # Caveat ID: time < 2025-01-01T00:00 # Caveat ID: operation = withdraw # Caveat ID: amount < 100 ``` -------------------------------- ### Verify Macaroon with Exact Predicates Source: https://context7.com/ecordell/pymacaroons/llms.txt Verifies a macaroon using exact string matching for caveat predicates. This is suitable when the exact caveat strings are known and expected. ```python from pymacaroons import Macaroon, Verifier from pymacaroons.exceptions import MacaroonInvalidSignatureException secret_key = 'this is our super secret key; only we should know it' m = Macaroon( location='http://mybank/', identifier='we used our secret key', key=secret_key ) m.add_first_party_caveat('account = 12345') m.add_first_party_caveat('action = view') v = Verifier() v.satisfy_exact('account = 12345') v.satisfy_exact('action = view') try: verified = v.verify(m, secret_key) print(f"Verified: {verified}") except MacaroonInvalidSignatureException as e: print(f"Invalid signature: {e}") try: v.verify(m, 'wrong key') except MacaroonInvalidSignatureException: print("Verification failed: signatures do not match") ``` -------------------------------- ### Handle Macaroon Exceptions Source: https://context7.com/ecordell/pymacaroons/llms.txt Catch specific library exceptions to manage errors during initialization or verification. ```python from pymacaroons import Macaroon, Verifier from pymacaroons.exceptions import ( MacaroonInitException, MacaroonSerializationException, MacaroonDeserializationException, MacaroonInvalidSignatureException, MacaroonUnmetCaveatException ) # MacaroonInitException - empty serialized data try: m = Macaroon.deserialize('') except MacaroonInitException as e: print(f"Init error: {e}") # Output: Init error: Must supply serialized macaroon. ``` -------------------------------- ### Verify a Macaroon Source: https://github.com/ecordell/pymacaroons/blob/master/README.md Use this to deserialize a macaroon and verify its integrity and caveats. You need to provide a verifier with functions or exact strings that satisfy the macaroon's caveats, along with the correct signing key. ```python n = Macaroon.deserialize("MDAyZWxvY2F0aW9uIGNvb2wtcGljdHVyZS1zZXJ2aWNlLmV4YW1wbGUuY29tCjAwMWJpZGVudGlmaWVyIGtleS1mb3ItYm9iCjAwMjdjaWQgcGljdHVyZV9pZCA9IGJvYnNfY29vbF9jYXQuanBnCjAwMmZzaWduYXR1cmUgg9j6KAsJk408_-BFY09UT_r3Ev8sUaw0goropCsnf48K") v = Verifier() def picture_access_validator(predicate): if predicate.split(' = ')[0] != 'picture_id': return False return predicate.split(' = ')[1] == 'bobs_cool_cat.jpg' v.satisfy_general(picture_access_validator) v.satisfy_exact('picture_id = bobs_cool_cat.jpg') verified = v.verify( n, keys[n.identifier] ) ``` -------------------------------- ### Add Third-Party Caveats Source: https://context7.com/ecordell/pymacaroons/llms.txt Delegate authorization to an external service by adding a third-party caveat that requires a discharge macaroon. ```python from pymacaroons import Macaroon # Primary macaroon from the target service m = Macaroon( location='http://mybank/', identifier='we used our other secret key', key='this is a different super-secret key; never use the same secret twice' ) # Add a first-party caveat m.add_first_party_caveat('account = 3735928559') # Add a third-party caveat requiring auth from another service # The caveat_key is shared with the third-party service caveat_key = '4; guaranteed random by a fair toss of the dice' identifier = 'this was how we remind auth of key/pred' m.add_third_party_caveat( location='http://auth.mybank/', # Third-party service location key=caveat_key, # Shared secret with third party key_id=identifier # Identifier for the caveat ) # Retrieve third-party caveats for caveat in m.third_party_caveats(): print(f"Location: {caveat.location}") print(f"Caveat ID: {caveat.caveat_id}") print(f"Has VID: {caveat.verification_key_id is not None}") # Output: # Location: http://auth.mybank/ # Caveat ID: this was how we remind auth of key/pred # Has VID: True ``` -------------------------------- ### Verify Macaroon with General Predicates Source: https://context7.com/ecordell/pymacaroons/llms.txt Verifies a macaroon using custom callback functions for complex caveat validation. This allows for logic like time checks, regex matching, or database lookups. ```python from pymacaroons import Macaroon, Verifier from datetime import datetime secret_key = 'this is our super secret key; only we should know it' m = Macaroon( location='http://mybank/', identifier='we used our secret key', key=secret_key ) m.add_first_party_caveat('account = 3735928559') m.add_first_party_caveat('time < 2030-01-01T00:00') m.add_first_party_caveat('ip = 192.168.1.0/24') ``` -------------------------------- ### Handle MacaroonUnmetCaveatException Source: https://context7.com/ecordell/pymacaroons/llms.txt Catch and print errors when verifying a macaroon without a required discharge macaroon. ```python m = Macaroon(location='test', identifier='id', key='secret') m.add_third_party_caveat('http://other/', 'caveat-key', 'caveat-id') v = Verifier(discharge_macaroons=[]) try: v.verify(m, 'secret') except MacaroonUnmetCaveatException as e: print(f"Caveat error: {e}") # Output: Caveat error: Caveat not met. No discharge macaroon found... ``` -------------------------------- ### Iterate and Inspect Caveats Source: https://context7.com/ecordell/pymacaroons/llms.txt Iterate through all caveats in a macaroon and inspect their properties. This is useful for understanding the structure of a macaroon and its associated restrictions. ```python from pymacaroons import Macaroon m = Macaroon( location='http://mybank/', identifier='key', key='secret' ) m.add_first_party_caveat('account = 12345') m.add_third_party_caveat('http://auth/', 'caveat-key', 'auth-required') # Iterate all caveats for caveat in m.caveats: print(f"Caveat ID: {caveat.caveat_id}") print(f"Is first-party: {caveat.first_party()}") print(f"Is third-party: {caveat.third_party()}") print(f"Location: {caveat.location}") print(f"Has verification key: {caveat.verification_key_id is not None}") print("---") # Output: # Caveat ID: account = 12345 # Is first-party: True # Is third-party: False # Location: # Has verification key: False # --- # Caveat ID: auth-required # Is first-party: False # Is third-party: True # Location: http://auth/ # Has verification key: True ``` -------------------------------- ### Copy Macaroons for Attenuation Source: https://context7.com/ecordell/pymacaroons/llms.txt Create deep copies of macaroons to add caveats without affecting the original instance. ```python from pymacaroons import Macaroon # Create a base macaroon base = Macaroon( location='http://mybank/', identifier='master-key', key='super-secret-key' ) base.add_first_party_caveat('account = 12345') # Create an attenuated copy for a specific use case restricted = base.copy() restricted.add_first_party_caveat('operation = read-only') restricted.add_first_party_caveat('time < 2025-06-01T00:00') # Original is unchanged print(len(base.caveats)) # 1 print(len(restricted.caveats)) # 3 # Signatures differ print(base.signature == restricted.signature) # False ``` -------------------------------- ### Deserialize Macaroon from Binary Source: https://context7.com/ecordell/pymacaroons/llms.txt Deserializes a macaroon from a binary string. The deserializer automatically detects whether the format is V1 or V2. ```python from pymacaroons import Macaroon serialized = 'MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVzZWQgb3VyIHNlY3JldCBrZXkKMDAxNmNpZCB0ZXN0ID0gY2F2ZWF0CjAwMmZzaWduYXR1cmUgGXusegRK8zMyhluSZuJtSTvdZopmDkTYjOGpmMI9vWcK' m = Macaroon.deserialize(serialized) print(m.location) print(m.identifier) print(m.signature) ``` -------------------------------- ### Handle MacaroonInvalidSignatureException Source: https://context7.com/ecordell/pymacaroons/llms.txt Catch and print errors when verifying a macaroon with an incorrect key. ```python m = Macaroon(location='test', identifier='id', key='secret') v = Verifier() try: v.verify(m, 'wrong-key') except MacaroonInvalidSignatureException as e: print(f"Signature error: {e}") # Output: Signature error: Signatures do not match ``` -------------------------------- ### Serialize Macaroons Source: https://context7.com/ecordell/pymacaroons/llms.txt Convert Macaroons into transportable formats like URL-safe base64 strings or JSON. ```python from pymacaroons import Macaroon, MACAROON_V1, MACAROON_V2 from pymacaroons.serializers import JsonSerializer, BinarySerializer import json m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it', version=MACAROON_V1 ) m.add_first_party_caveat('test = caveat') # Default binary serialization (URL-safe base64, no padding) serialized = m.serialize() print(serialized) # Output: MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVz... ``` -------------------------------- ### Handle MacaroonDeserializationException Source: https://context7.com/ecordell/pymacaroons/llms.txt Catch and print errors when deserializing macaroons with invalid data. ```python try: m = Macaroon.deserialize('invalid-data') except MacaroonDeserializationException as e: print(f"Deserialize error: {e}") ``` -------------------------------- ### Serialize Macaroon to JSON (V1) Source: https://context7.com/ecordell/pymacaroons/llms.txt Serializes a macaroon object into the V1 JSON format. Use this when you need to represent macaroons in a human-readable JSON structure. ```python from pymacaroons.serializers import JsonSerializer # Assuming 'm' is a Macaroon object json_serialized = m.serialize(serializer=JsonSerializer()) print(json.loads(json_serialized)) ``` -------------------------------- ### Deserialize Macaroon from JSON (V1) Source: https://context7.com/ecordell/pymacaroons/llms.txt Deserializes a macaroon from a V1 JSON string using the JsonSerializer. Ensure the input string conforms to the V1 JSON structure. ```python from pymacaroons import Macaroon from pymacaroons.serializers import JsonSerializer json_str = '{"location": "http://mybank/", "identifier": "we used our secret key", "signature": "197bac7a044af33332865b9266e26d493bdd668a660e44d88ce1a998c23dbd67", "caveats": [{"cid": "test = caveat", "vid": null, "cl": null}]}' m_json = Macaroon.deserialize(json_str, serializer=JsonSerializer()) print(m_json.signature) ``` -------------------------------- ### Inspect Macaroon Details Source: https://context7.com/ecordell/pymacaroons/llms.txt Generates a human-readable string representation of a macaroon, including its location, identifier, caveats, and signature. Useful for debugging. ```python from pymacaroons import Macaroon m = Macaroon( location='cool-picture-service.example.com', identifier='key-for-bob', key='asdfasdfas-a-very-secret-signing-key' ) m.add_first_party_caveat('picture_id = bobs_cool_cat.jpg') m.add_first_party_caveat('time < 2025-01-01T00:00') print(m.inspect()) ``` -------------------------------- ### Serialize Macaroon to JSON (V2) Source: https://context7.com/ecordell/pymacaroons/llms.txt Serializes a macaroon object into the V2 JSON format, which uses compact field names. This is useful for reducing the size of the serialized macaroon. ```python from pymacaroons import Macaroon from pymacaroons.serializers import JsonSerializer m_v2 = Macaroon( location='http://mybank/', identifier='key-v2', key='secret-key-v2', version=MACAROON_V2 ) json_v2 = m_v2.serialize(serializer=JsonSerializer()) print(json.loads(json_v2)) ``` -------------------------------- ### Deserialize Macaroon from JSON (V2) Source: https://context7.com/ecordell/pymacaroons/llms.txt Deserializes a macaroon from a V2 JSON string using the JsonSerializer. V2 uses compact field names for efficiency. ```python from pymacaroons import Macaroon from pymacaroons.serializers import JsonSerializer json_v2 = '{"l": "http://mybank/", "i": "we used our secret key", "s": "197bac7a044af33332", "c": [{"i": "test = caveat"}]}' m_v2 = Macaroon.deserialize(json_v2, serializer=JsonSerializer()) print(m_v2.version) ``` -------------------------------- ### Filter Caveats by Type Source: https://context7.com/ecordell/pymacaroons/llms.txt Filter macaroons to retrieve only first-party or third-party caveats. This is useful when specific processing is required based on the caveat type. ```python # Filter by caveat type first_party = m.first_party_caveats() # List of first-party caveats third_party = m.third_party_caveats() # List of third-party caveats ``` -------------------------------- ### Perform Multi-Level Discharge Verification Source: https://context7.com/ecordell/pymacaroons/llms.txt Handle chained third-party caveats where a discharge macaroon requires its own discharge. ```python from pymacaroons import Macaroon, Verifier # Root service creates macaroon requiring Bob's authorization root = Macaroon(location="", identifier="root-id", key="root-key") root.add_third_party_caveat("bob", "bob-caveat-root-key", "bob-is-great") # Bob's service creates discharge but requires Barbara's authorization discharge1 = Macaroon( location="bob", identifier="bob-is-great", key="bob-caveat-root-key" ) discharge1.add_third_party_caveat( "barbara", "barbara-caveat-root-key", "barbara-is-great" ) # Barbara's service creates the final discharge discharge2 = Macaroon( location="barbara", identifier="barbara-is-great", key="barbara-caveat-root-key" ) # Prepare all discharge macaroons for request discharge1 = root.prepare_for_request(discharge1) discharge2 = root.prepare_for_request(discharge2) # Verify the complete chain verified = Verifier( discharge_macaroons=[discharge1, discharge2] ).verify(root, "root-key") print(f"Verified: {verified}") # Output: Verified: True ``` -------------------------------- ### Define Custom Caveat Validators Source: https://context7.com/ecordell/pymacaroons/llms.txt Implement custom logic for verifying caveats by passing validator functions to the Verifier instance. ```python def time_caveat_validator(predicate): if not predicate.startswith('time < '): return False expiry = datetime.fromisoformat(predicate.split(' < ')[1]) return datetime.now() < expiry def ip_caveat_validator(predicate): if not predicate.startswith('ip = '): return False # Check if request IP is in allowed subnet allowed_subnet = predicate.split(' = ')[1] request_ip = '192.168.1.100' # From request context return request_ip.startswith(allowed_subnet.rsplit('.', 1)[0]) def account_validator(predicate): if not predicate.startswith('account = '): return False account_id = predicate.split(' = ')[1] # Verify account exists and is active return account_id == '3735928559' v = Verifier() v.satisfy_general(time_caveat_validator) v.satisfy_general(ip_caveat_validator) v.satisfy_general(account_validator) verified = v.verify(m, secret_key) print(f"Verified: {verified}") # Output: Verified: True ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.