diff --git a/examples/python-flask/README.md b/examples/python-flask/README.md index 1c5ac97..e65f5fc 100644 --- a/examples/python-flask/README.md +++ b/examples/python-flask/README.md @@ -19,3 +19,68 @@ $ poetry install ```bash $ poetry run main ``` + +## Step-By-Step + +First, open your browser on the selected host (default is http://localhost:5001) + +Note: This flask exemple creates a DID by default in key.jwk + +From there, you should see 4 options available: + +1. Issue Verifiable Credential +2. Verify Verifiable Credential +3. Issue Verifiable Presentation +4. Verify Verifiable Presentation + +### Issue a Verifiable Credential (VC) +The first step should be to generate a Verifiable Credential. To understand better +what a VC is, please refer to SpruceID Glossary [here](https://www.spruceid.dev/references/glossary#verifiable-credentials-vcs) + +In order to simplify this example, there are only 2 ways to issue a VC: + +1. Read a QRcode via Credible +2. Get server issued credential + +On a real case scenario, a unsigned credential would be required so DIDKit can sign it. +One can refer to this in the quickstart example [here](https://www.spruceid.dev/quickstart) + +The issued VC will be presented in JSON format. Store this value for later use. + +### Verify a Verifiable Credential (VC) +After successfully issuing a VC, the next step should be to verify it. + +Copy and paste the issued VC from the first step and click on the button to verify it. +The default response should be: +```json +{ + "checks":["proof"], + "errors":[], + "warnings":[] +} +``` +This means the given VC is valid. + +### Issue a Verifiable Presentation (VP) +Now, one can use the valid VC to generate a Verifiable Presentation. To understand better +what a VP is, please refer to W3C exemple [here](https://www.w3.org/TR/vc-data-model-2.0/#dfn-verifiable-presentation) + +Note: in very brief terms, a VP can contain cherry-picked information from the original VC +in order to preserve sensitive/unwanted verifiable information + +To generate a VP using DIDKit, 3 variables are needed: +1. The unsigned VP +2. A valid VC +3. The VC holder identifier (in this example, a DID:key) + +One can refer to this in the CLI example [here](https://www.spruceid.dev/didkit/didkit-examples/core-functions-cli#create-a-verifiable-presentation-that-embeds-the-verifiable-credential) + +The default response should be: +```json +{ + "checks":["proof"], + "errors":[], + "warnings":[] +} +``` +This means the given VP is valid. diff --git a/examples/python-flask/didkit_flask/issue_credential.py b/examples/python-flask/didkit_flask/issue_credential.py index 5cfb1d5..102e8ce 100644 --- a/examples/python-flask/didkit_flask/issue_credential.py +++ b/examples/python-flask/didkit_flask/issue_credential.py @@ -6,6 +6,15 @@ async def req_issue_vc(request): + """Issues a Verifiable VC using SpruceID DIDKit + Args: + request (flask.Request): Flask API request containing + None (Issue via server) or + QRcode url + + Returns: + Dict: Generated VC from DIDKit issue_credential + """ with open("key.jwk", "r") as f: key = f.readline() f.close() diff --git a/examples/python-flask/didkit_flask/issue_presentation.py b/examples/python-flask/didkit_flask/issue_presentation.py new file mode 100644 index 0000000..4e7d648 --- /dev/null +++ b/examples/python-flask/didkit_flask/issue_presentation.py @@ -0,0 +1,35 @@ + +from didkit import issue_presentation, key_to_verification_method +import json + + +async def issue_vp_credential(request): + """Issue a VP credential using SpruceID DIDKit + + Args: + request (flask.Request): Flask API request containing: + Unsigned VP, + Signed VC, + Holder info + + Returns: + Dict: Python dict containing a valid DIDKit VP + """ + with open("key.jwk", "r") as f: + key = f.readline() + f.close() + verification_method = await key_to_verification_method("key", key) + didkit_options = { + "proofPurpose": "assertionMethod", + "verificationMethod": verification_method, + } + vp = json.loads(request.form.get("input_vp")) + vc = json.loads(request.form.get("input_vc")) + holder = request.form.get("holder") + + vp["verifiableCredential"] = vc + vp["holder"] = holder + + presentation = await issue_presentation(json.dumps(vp), + json.dumps(didkit_options), key) + return json.loads(presentation) diff --git a/examples/python-flask/didkit_flask/main.py b/examples/python-flask/didkit_flask/main.py index b9c957a..d1dfaab 100644 --- a/examples/python-flask/didkit_flask/main.py +++ b/examples/python-flask/didkit_flask/main.py @@ -8,6 +8,9 @@ from flask_qrcode import QRcode from didkit_flask.issue_credential import req_issue_vc +from didkit_flask.verify_credential import verify_vc_credential +from didkit_flask.issue_presentation import issue_vp_credential +from didkit_flask.verify_presentation import verify_vp_credential app = Flask(__name__) qrcode = QRcode(app) @@ -37,7 +40,9 @@ def index(): @app.route("/credential", methods=["GET", "POST"]) async def credential(): - credential = json.dumps(await req_issue_vc(request), indent=2, sort_keys=True) + credential = json.dumps(await req_issue_vc(request), + indent=2, + sort_keys=True) return render_template("credential.html", credential=credential) @@ -46,11 +51,44 @@ async def credential(): async def wallet(): credential = await req_issue_vc(request) if request.method == "GET": - return jsonify({"type": "CredentialOffer", "credentialPreview": credential}) + return jsonify({"type": "CredentialOffer", + "credentialPreview": credential}) elif request.method == "POST": return jsonify(credential) +@app.route("/issue_vc", methods=["GET"]) +async def issue_vc(): + return render_template("issue_vc.html") + + +@app.route("/verify_vc", methods=["GET", "POST"]) +async def verify_vc(): + if request.method == "GET": + return render_template("verify_vc.html") + elif request.method == "POST": + validation = await verify_vc_credential(request) + return jsonify(validation) + + +@app.route("/issue_vp", methods=["GET", "POST"]) +async def issue_vp(): + if request.method == "GET": + return render_template("issue_vp.html") + elif request.method == "POST": + presentation = await issue_vp_credential(request) + return jsonify(presentation) + + +@app.route("/verify_vp", methods=["GET", "POST"]) +async def verify_vp(): + if request.method == "GET": + return render_template("verify_vp.html") + elif request.method == "POST": + presentation = await verify_vp_credential(request) + return jsonify(presentation) + + def main(): flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY try: diff --git a/examples/python-flask/didkit_flask/templates/index.html b/examples/python-flask/didkit_flask/templates/index.html index c1c7a10..acb8c46 100644 --- a/examples/python-flask/didkit_flask/templates/index.html +++ b/examples/python-flask/didkit_flask/templates/index.html @@ -3,28 +3,40 @@
-or scan the QRCode bellow with your wallet. i.e: Credible
-or
- - - + + + +