22 | This verifiable credential includes a photo claim that you can be used for biometric face check during presentation. You can either take a selfie or upload an existing picture of you before you issue the credential.
23 |
24 | For selfie, click the Take Selfie button, then scan the QR code with the QR Code Reader app on your mobile, click 'Open Camera' in the page, take selfie and then click 'Use photo' in the mobile.
25 | The photo is not persisted anywhere and is just added to the credential you will have in your wallet.
26 |
27 | Then click Issue Credential to start the issuance process. When the QR code appears, scan it with your Microsoft Authenticator or your custom wallet app.
28 |
29 | The photo should be a portrait photo of atleast 200x200 pixels. Glasses, masks, hats, headphones, head coverings and face coverings will result in failure in liveness checks during presentations.
30 |
" -Path createdApps.html
134 |
135 | # Update config file for the app
136 | $configFile = $pwd.Path + "$([IO.Path]::DirectorySeparatorChar)..$([IO.Path]::DirectorySeparatorChar)config.json"
137 | Write-Host "Updating the sample code ($configFile)"
138 | $dictionary = @{ "azTenantId" = $tenantId; "azClientId" = $clientAadApplication.AppId; "azClientSecret" = $client_secret;
139 | "azCertificateName" = $certSubject; "azCertificateLocation" = $certLocation.Replace("\", "\\"); "azCertificatePrivateKeyLocation" = $certPrivateKey.Replace("\", "\\")
140 | };
141 | UpdateTextFile -configFilePath $configFile -dictionary $dictionary
142 | Write-Host ""
143 | Write-Host "IMPORTANT: Please follow the instructions below to complete a few manual step(s) in the Azure portal":
144 | Write-Host "- For '$appName'"
145 | Write-Host " - Navigate to $clientPortalUrl"
146 | Write-Host " - Click on 'Grant admin consent for $tenantName' in the API Permissions page"
147 |
--------------------------------------------------------------------------------
/1-python-api-idtokenhint/public/presentation-verified.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 | Verifiable Credential Expert Request API Sample - Verifier
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
VerifiedEmployee Presentation
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
Claims
Value
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
VC Details
Value
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/1-python-api-idtokenhint/AppCreationScripts/README.md:
--------------------------------------------------------------------------------
1 | # Registering the Azure Active Directory applications and updating the configuration files for this sample using PowerShell scripts
2 |
3 | ## Overview
4 |
5 | ### Quick summary
6 |
7 | 1. On Windows run PowerShell, navigate to the root of the cloned directory and then run the command:
8 | ```PowerShell
9 | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force
10 | ```
11 | 1. On Mac/Linux, open a terminal, navigate to the root of the cloned directory, and then run command `pwsh` to start Powershell Core. You do not need to .run the `Set-ExecutionPolicy`
12 | 1. If you plan to use a client secret to authenticate the app (which is the default), you can skip this step. On Windows, if you plan to use app authentication via a self-signed certificate, you need to generate the certificate using `openssl` either using Windows Subsystem for Linux or on a Mac/Linux and then copy the files to your Windows computer. Please see details below and complete this step before continuing.
13 | 1. Run the script to create your Azure AD application and configure the code of the sample application accordinly. (Other ways of running the scripts are described below)
14 | ```PowerShell
15 | cd AppCreationScripts
16 | ./Configure.ps1
17 | ```
18 | 1. Update the `config.json` with the CredentialManifest, IssuerAuthority and VerifierAuthority details
19 | 1. Run the solution via executing `run.cmd` on Windows or `run.sh` on Mac/Linux
20 |
21 | ### Generating Self-Signed Certificate on Windows
22 |
23 | If you plan to use a self-signed certificate for app authentication ***and*** you are using a Windows computer, you need to manually generate the certificate using `openssl` ***before*** you run the Configure.ps1 script. If you are on a Mac/Linux, you don't need to do this manually as it is being done as part of the Configure.ps1 script. There are two ways of generating the self-signed certificate:
24 |
25 | If you have Windows Subsystem for Linux (WSL) enabled on your Windows computer, you can use it. Start WSL and navigate to the AppCreationScripts folder. If you don't have WSL, you need to use a Mac/Linux computer to run the below commands. After the commands have completed, you need to copy the files `aadappcert.pem` and `aadappcert.crt` from your Mac/Linux to your Windows computer.
26 |
27 | ```bash
28 | openssl genrsa -out ./aadappcert.pem 2048
29 | openssl req -new -key ./aadappcert.pem -out ./aadappcert.csr -subj "/CN=vcpythonsample"
30 | openssl x509 -req -days 365 -in ./aadappcert.csr -signkey ./aadappcert.pem -out ./aadappcert.crt
31 | ```
32 |
33 | If you need to install openssl, you can do it via the below command
34 |
35 | In WSL/Ubuntu
36 |
37 | ```bash
38 | sudo apt-get install openssl
39 | ```
40 |
41 | On a Mac, you install openssl via brew
42 |
43 | ```bash
44 | brew install openssl
45 | ```
46 |
47 | ### More details
48 |
49 | The following paragraphs:
50 |
51 | - [Present the scripts](#presentation-of-the-scripts) and explain their [usage patterns](#usage-pattern-for-tests-and-devops-scenarios) for test and DevOps scenarios.
52 | - Explain the [pre-requisites](#pre-requisites)
53 | - Explain [different ways of running the scripts](#different-ways-of-running-the-scripts):
54 |
55 | ## Goal of the scripts
56 |
57 | ### Presentation of the scripts
58 |
59 | This sample comes with two PowerShell scripts, which automate the creation of the Azure Active Directory applications, and the configuration of the code for this sample. Once you run them, you will only need to build the solution and you are good to test.
60 |
61 | These scripts are:
62 |
63 | - `Configure.ps1` which:
64 | - creates Azure AD applications and their related objects (permissions, dependencies, secrets/certificate),
65 | - changes the configuration file `config.json` in the sample code.
66 | - creates a summary file named `createdApps.html` in the folder from which you ran the script, and containing, for each Azure AD application it created:
67 | - the identifier of the application
68 | - the AppId of the application
69 | - the url of its registration in the [Azure portal](https://portal.azure.com).
70 |
71 | - `Cleanup.ps1` which cleans-up the Azure AD objects created by `Configure.ps1`, including deleting the certificate files in the directory. Note that this script does not revert the changes done in the configuration files, though. You will need to undo the change from source control (from VSCode, or from the command line using, for instance, git reset).
72 |
73 | ## How to use the app creation scripts ?
74 |
75 | ### Pre-requisites
76 |
77 | You must have Powershell installed on your machine. To install it, follow the documentation:
78 | - [Windows](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.2)
79 | - [Mac](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-macos?view=powershell-7.2)
80 | - [Linux](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-linux?view=powershell-7.2)
81 |
82 | ### Install Az PowerShell modules
83 | The scripts required PowerShell module Az. To install it, follow the documentation [here](https://docs.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-7.1.0). If you have installed it previously, make sure that you have the latest version by running Powershell command. The Configure.ps1 script may give an error if you have an old version.
84 |
85 | ```powershell
86 | Update-Module -Name Az
87 | ```
88 | If you do need to run `Update-Module` on Mac/Linux, you need to exit the Powershell shell `pwsh` and enter it again.
89 |
90 | ### openssl on Mac/Linux
91 |
92 | If you are running the `Configure.ps1` script on a Mac/Linux, and you plan to use the option of authenticating as the app using a client certificate, you need to install `openssl` on your computer. How you do this varies with what Linux distro you are using, but on Ubunto, you install openssl by running this in the terminal window
93 |
94 | ```bash
95 | sudo apt-get install openssl
96 | ```
97 |
98 | On a Mac, you install openssl via brew
99 |
100 | ```bash
101 | brew install openssl
102 | ```
103 |
104 | ### Different ways of running the scripts
105 |
106 | Using the parameters, the script can be run in the following different ways. Depending on if you haven't signed in from the powershell prompt yet, you will be required to do an interactive signin. If you already have signed in, the script will execute in the current context. You can check if you have a current context via the `Get-AzContext` powershell command. This will show which Azure AD tenant you are currently signed in to. If this is the wrong Azure AD tenant, you can clear the current context with the `Clear-AzContext`.
107 |
108 | If you don't want to sign in every time you execute a script, you can to this via running the following
109 |
110 | ```powershell
111 | $tenantId = "yourTenantIdGuid"
112 | Connect-AzConnect -tenantId $tenantId
113 | ```
114 |
115 | #### Option 1
116 |
117 | Running the script without any parameters will use the current context, if it exist, or ask the user to sign in interactively.
118 |
119 | ```powershell
120 | .\Configure.ps1
121 | ```
122 |
123 | #### Option 2 - specify tenant
124 |
125 | Running the script and specifying the tenantId will check that the current is for the specified Azure AD tenant and exit if it is not. If an interactive sign in is needed, it will be for the Azure AD tenant specified in the parameter. Specifying the tenant explicitly avoids accidentally running the script in the wrong tenant.
126 |
127 | ```powershell
128 | .\Configure.ps1 -tenantId $tenantId
129 | ```
130 |
131 | #### Option 3 - specify type of app credentials
132 |
133 | The default behaviour of the `Configure.ps1` script is to register the app and create a `client secret` as it's credentials. This allows the sample app to authenticate using a client_id and a client_secret. If you instead prefer that the app authenticates via a `client certificate`, you can let the script generate a self-signed certificate and upload it to the app registration. There is also the possibility of creating both a client secret
134 |
135 | ```powershell
136 | .\Configure.ps1 -ClientCertificate
137 | ```
138 |
139 | ```powershell
140 | .\Configure.ps1 -ClientCertificate -ClientSecret
141 | ```
142 |
143 | If you use the `-ClientCertificate` option, on Windows, the script will create a self-signed certificate in the user certificate store under Personal\Certificates with the subject `CN=vcaspnetcoresample`. On Mac/Linux, the self-signed certificate will be three files named appaadcert.pem, appaadcert.csr and addaadcert.csr. The `Cleanup.ps1` script will remove the certificate from the certificate store on Windows and delete the files on Mac/Linux.
144 |
145 | #### Option 4 - Cleanup
146 |
147 | This option is if you need cleanup after you are done testing or if you need to re-run the script. The `-ClientCertificate` and `-ClientSecret` parameters are just there for reference to show how it could look.
148 |
149 | ```PowerShell
150 | $tenantId = "yourTenantIdGuid"
151 | . .\Cleanup.ps1 -TenantId $tenantId
152 | . .\Configure.ps1 -TenantId $tenantId -ClientCertificate -ClientSecret
153 | ```
154 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Microsoft Entra Verified ID Samples
2 |
3 | This repo contains a set of Microsoft Entra Verified ID samples (former Azure AD Verifiable Credentials)
4 |
5 | ## Samples
6 | | Sample | Description |
7 | |------|--------|
8 | | 1-python-api-idtokenhint | Python sample for using the VC Request Service API to issue and verify verifiable credentials with a credential contract which allows the VC Request API to pass in a payload for the Verifiable Credentials|
9 |
10 |
11 |
12 | Microsoft provides a simple to use REST API to issue and verify verifiable credentials. You can use the programming language you prefer to the REST API. Instead of needing to understand the different protocols and encryption algoritms for Verifiable Credentials and DIDs you only need to understand how to format a JSON structure as parameter for the VC Request API.
13 |
14 | 
15 |
16 | ## Issuance
17 |
18 | ### Issuance JSON structure
19 |
20 | To call the VC Client API to start the issuance process, the VC Request API needs a JSON structure payload like below.
21 |
22 | ```JSON
23 | {
24 | "authority": "did:ion: ...of the Issuer",
25 | "includeQRCode": true,
26 | "registration": {
27 | "clientName": "the verifier's client name"
28 | },
29 | "callback": {
30 | "url": "https://contoso.com/api/issuer/issuanceCallback",
31 | "state": "you pass your state here to correlate it when you get the callback",
32 | "headers": {
33 | "api-key": "API key to help protect your callback API"
34 | }
35 | },
36 | "type": "your credentialType",
37 | "manifest": "https://verifiedid.did.msidentity.com/v1.0/3c32ed40-8a10-465b-8ba4-0b1e86882668/verifiableCredential/contracts/VerifiedCredentialExpert",
38 | "pin": {
39 | "value": "012345",
40 | "length": 6
41 | },
42 | "claims": {
43 | "firstName": "Megan",
44 | "lastName": "Bowen"
45 | }
46 | }
47 | ```
48 |
49 | - **authority** - is the DID identifier for your registered Verifiable Credential from portal.azure.com.
50 | - **includeQRCode** - If you want the VC Client API to return a `data:image/png;base64` string of the QR code to present in the browser. If you select `false`, you must create the QR code yourself (which is not difficult).
51 | - **registration.clientName** - name of your app which will be shown in the Microsoft Authenticator
52 | - **callback.url** - a callback endpoint in your application. The VC Request API will call this endpoint when the issuance is completed.
53 | - **callback.state** - A state value you provide so you can correlate this request when you get callback confirmation
54 | - **callback.headers** - Any HTTP Header values that you would like the VC Request API to pass back in the callbacks. Here you could set your own API key, for instance
55 | - **type** - the name of your credentialType. This value is configured in the rules file.
56 | - **manifest** - url of your manifest for your VC. This comes from your defined Verifiable Credential in portal.azure.com
57 | - **pin** - If you want to require a pin code in the Microsoft Authenticator for this issuance request. This can be useful if it is a self issuing situation where there is no possibility of asking the user to prove their identity via a login. If you don't want to use the pin functionality, you should not have the pin section in the JSON structure.
58 | - **claims** - optional, extra claims you want to include in the VC.
59 |
60 | In the response message from the VC Request API, it will include a URL to the request which is hosted at the Microsoft VC request service, which means that once the Microsoft Authenticator has scanned the QR code, it will contact the VC Request service directly and not your application directly. Your application will get a callback from the VC Request service via the callback.
61 |
62 | ```json
63 | {
64 | "requestId": "799f23ea-524a-45af-99ad-cf8e5018814e",
65 | "url": "openid://vc?request_uri=https://verifiedid.did.msidentity.com/v1.0/abc/verifiablecredentials/request/178319f7-20be-4945-80fb-7d52d47ae82e",
66 | "expiry": 1622227690,
67 | "qrCode": "data:image/png;base64,iVBORw0KGgoA"
68 | }
69 | ```
70 |
71 | ### Issuance Callback
72 |
73 | In your callback endpoint, you will get a callback with the below message when the QR code is scanned. This callback is typically used to modify the UI, hide the QR code to prevent scanning again and show the pincode to use when the user wants to accept the Verifiable Credential.
74 |
75 | ```JSON
76 | {
77 | "requestStatus":"request_retrieved",
78 | "requestId":"9463da82-e397-45b6-a7a2-2c4223b9fdd0",
79 | "state": "...what you passed as the state value..."
80 | }
81 | ```
82 |
83 | Once the VC is issued, you get a second callback which contains information if the issuance of the verifiable credential to the user was succesful or not.
84 |
85 | This callback is typically used to notify the user on the issuance website the process is completed and continue with whatever the website needs or wants the user to do.
86 |
87 | ### Successful Issuance flow response
88 | ```JSON
89 | {
90 | "requestStatus":"issuance_successful",
91 | "requestId":"9463da82-e397-45b6-a7a2-2c4223b9fdd0",
92 | "state": "...what you passed as the state value..."
93 | }
94 | ```
95 | ### Unuccesful Issuance flow response
96 | ```JSON
97 | {
98 | "requestStatus":"issuance_failed",
99 | "requestId":"9463da82-e397-45b6-a7a2-2c4223b9fdd0",
100 | "state": "...what you passed as the state value...",
101 | "error": {
102 | "code":"IssuanceFlowFailed",
103 | "message":"issuance_service_error",
104 | }
105 | }
106 | ```
107 | When the issuance fails this can be caused by several reasons. The following details are currently provided in the error part of the response:
108 | | Message | Definition |
109 | |---|---|
110 | | fetch_contract_error | The user has canceled the flow |
111 | | issuance_service_error | VC Issuance service was not able to validate requirements / something went wrong on Microsoft AAD VC Issuance service side. |
112 | | unspecified_error | Something went wrong that doesn’t fall into this bucket |
113 |
114 |
115 | ## Verification
116 |
117 | ### Verification JSON structure
118 |
119 | To call the VC Request API to start the verification process, the application creates a JSON structure like below. Since the WebApp asks the user to present a VC, the request is also called `presentation request`.
120 |
121 | ```JSON
122 | {
123 | "authority": "did:ion: did-of-the-Verifier",
124 | "includeQRCode": true,
125 | "registration": {
126 | "clientName": "the verifier's client name",
127 | "purpose": "the purpose why the verifier asks for a VC"
128 | },
129 | "callback": {
130 | "url": "https://contoso.com/api/verifier/presentationCallback",
131 | "state": "you pass your state here to correlate it when you get the callback",
132 | "headers": {
133 | "api-key": "API key to help protect your callback API"
134 | }
135 | },
136 | "includeReceipt": false,
137 | "requestedCredentials": [
138 | {
139 | "type": "your credentialType",
140 | "purpose": "the purpose why the verifier asks for a VC",
141 | "acceptedIssuers": [ "did:ion: ...of the Issuer" ],
142 | "configuration": {
143 | "validation": {
144 | "allowRevoked": true,
145 | "validateLinkedDomain": true
146 | }
147 | }
148 | }
149 | ]
150 | }
151 | ```
152 |
153 | Much of the data is the same in this JSON structure, but some differences needs explaining.
154 |
155 | - **authority** vs **acceptedIssuers** - The Verifier and the Issuer may be two different entities. For example, the Verifier might be a online service, like a car rental service, while the DID it is asking for is the issuing entity for drivers licenses. Note that `acceptedIssuers` is a collection of DIDs, which means you can ask for multiple VCs from the user coming from different trusted issuers.
156 | - **requestedCredentials** - please also note that the `requestedCredentials` is a collection too, which means you can ask to create a presentation request that contains multiple DIDs.
157 | - **includeReceipt** - if set to true, the `presentation_verified` callback will contain the `receipt` element.
158 |
159 | ### Verification Callback
160 |
161 | In your callback endpoint, you will get a callback with the below message when the QR code is scanned.
162 |
163 | When the QR code is scanned, you get a short callback like this.
164 | ```JSON
165 | {
166 | "requestStatus":"request_retrieved",
167 | "requestId":"c18d8035-3fc8-4c27-a5db-9801e6232569",
168 | "state": "...what you passed as the state value..."
169 | }
170 | ```
171 |
172 | Once the VC is verified, you get a second, more complete, callback which contains all the details on what whas presented by the user.
173 |
174 | ```JSON
175 | {
176 | "requestStatus":"presentation_verified",
177 | "requestId":"c18d8035-3fc8-4c27-a5db-9801e6232569",
178 | "state": "...what you passed as the state value...",
179 | "subject": "did:ion: ... of the VC holder...",
180 | "issuers": [
181 | {
182 | "issuer": "did:ion of the issuer of this verifiable credential ",
183 | "type": [ "VerifiableCredential", "your credentialType" ],
184 | "claims": {
185 | "lastName":"Bowen",
186 | "firstName":"Megan"
187 | },
188 | "credentialState": {
189 | "revocationStatus": "VALID"
190 | },
191 | "domainValidation": {
192 | "url": "https://did.woodgrovedemo.com"
193 | }
194 | }
195 | ],
196 | "receipt":{
197 | "id_token": "...JWT Token of VC...",
198 | "vp_token": "...JWT Token of VP..."
199 | }
200 | }
201 | }
202 | ```
203 | Some notable attributes in the message:
204 | - **claims** - parsed claims from the VC
205 | - **credentialState.revocationStatus** - indicates the current revocation status at the time of the presentaion
206 | - **domainValidation** - If you asked for domain validation via passing `validateLinkedDomain` **true** in the request, you will get the validated domain name in the response.
207 | - **receipt.id_token** - The JWT token of the presentation response
208 | - **receipt.vp_token** - The JWT token of the credential in the presentation response. In the token, the `vp.verifiableCredential` contains the VCs for the presented credentials.
209 |
210 |
211 | ## Setup
212 |
213 | Before you can run any of these samples make sure your environment is setup correctly. You can follow the setup instructions [here](https://aka.ms/vcsetup)
214 |
215 | ## Resources
216 |
217 | For more information, see MSAL.NET's conceptual documentation:
218 |
219 | - [Quickstart: Register an application with the Microsoft identity platform](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app)
220 | - [Quickstart: Configure a client application to access web APIs](https://docs.microsoft.com/azure/active-directory/develop/quickstart-configure-app-access-web-apis)
221 | - [Acquiring a token for an application with client credential flows](https://aka.ms/msal-net-client-credentials)
222 |
--------------------------------------------------------------------------------
/1-python-api-idtokenhint/ARMTemplate/template.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "webAppName": {
6 | "type": "string",
7 | "defaultValue": "",
8 | "minLength": 2,
9 | "metadata": {
10 | "description": "app name."
11 | }
12 | },
13 | "repoURL": {
14 | "type": "string",
15 | "metadata": {
16 | "description": "Github repo URL"
17 | },
18 | "defaultValue": "https://github.com/Azure-Samples/active-directory-verifiable-credentials-python.git"
19 | },
20 | "branch": {
21 | "type": "string",
22 | "metadata": {
23 | "description": "Github repo branch"
24 | },
25 | "defaultValue": "main"
26 | },
27 | "Project": {
28 | "type": "string",
29 | "metadata": {
30 | "description": "Github repo subfolder"
31 | },
32 | "defaultValue": "1-python-api-idtokenhint"
33 | },
34 | "azTenantId": {
35 | "type": "string",
36 | "metadata": {
37 | "description": "Entra ID Tenant id"
38 | },
39 | "defaultValue": ""
40 | },
41 | "azClientId": {
42 | "type": "string",
43 | "metadata": {
44 | "description": "azClientId"
45 | },
46 | "defaultValue": ""
47 | },
48 | "azClientSecret": {
49 | "type": "string",
50 | "metadata": {
51 | "description": "azClientSecret"
52 | },
53 | "defaultValue": ""
54 | },
55 | "DidAuthority": {
56 | "type": "string",
57 | "metadata": {
58 | "description": "DidAuthority"
59 | },
60 | "defaultValue": ""
61 | },
62 | "CredentialManifest": {
63 | "type": "string",
64 | "metadata": {
65 | "description": "CredentialManifest"
66 | },
67 | "defaultValue": ""
68 | },
69 | "CredentialType": {
70 | "type": "string",
71 | "metadata": {
72 | "description": "CredentialType"
73 | },
74 | "defaultValue": "VerifiedCredentialExpert"
75 | },
76 | "PhotoClaimName": {
77 | "type": "string",
78 | "metadata": {
79 | "description": "claim name for photo - if you are using FaceCheck during presentation. Otherwise leave this field blank"
80 | },
81 | "defaultValue": ""
82 | }
83 | },
84 | "variables": {
85 | "appServicePlanPortalName": "[concat(parameters('webAppName'), '-plan')]",
86 | "linuxFxVersion": "PYTHON|3.12"
87 | },
88 | "resources": [
89 | {
90 | "type": "Microsoft.Web/serverfarms",
91 | "apiVersion": "2020-06-01",
92 | "name": "[variables('appServicePlanPortalName')]",
93 | "location": "[resourceGroup().location]",
94 | "sku": {
95 | "name": "B1",
96 | "tier": "Basic",
97 | "size": "B1",
98 | "family": "B",
99 | "capacity": 1
100 | },
101 | "properties": {
102 | "perSiteScaling": false,
103 | "elasticScaleEnabled": false,
104 | "maximumElasticWorkerCount": 1,
105 | "isSpot": false,
106 | "reserved": true,
107 | "isXenon": false,
108 | "hyperV": false,
109 | "targetWorkerCount": 0,
110 | "targetWorkerSizeId": 0,
111 | "zoneRedundant": false
112 | },
113 | "kind": "linux"
114 | },
115 |
116 | {
117 | "type": "Microsoft.Web/sites",
118 | "apiVersion": "2022-09-01",
119 | "name": "[parameters('webAppName')]",
120 | "location": "[resourceGroup().location]",
121 | "kind": "app,linux",
122 | "dependsOn": [
123 | "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanPortalName'))]"
124 | ],
125 | "properties": {
126 | "enabled": true,
127 | "hostNameSslStates": [
128 | {
129 | "name": "[concat(parameters('webAppName'), '.azurewebsites.net')]",
130 | "sslState": "Disabled",
131 | "hostType": "Standard"
132 | },
133 | {
134 | "name": "[concat(parameters('webAppName'), '.scm.azurewebsites.net')]",
135 | "sslState": "Disabled",
136 | "hostType": "Repository"
137 | }
138 | ],
139 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanPortalName'))]",
140 | "reserved": true,
141 | "isXenon": false,
142 | "hyperV": false,
143 | "vnetRouteAllEnabled": false,
144 | "vnetImagePullEnabled": false,
145 | "vnetContentShareEnabled": false,
146 | "siteConfig": {
147 | "numberOfWorkers": 1,
148 | "linuxFxVersion": "[variables('linuxFxVersion')]",
149 | "acrUseManagedIdentityCreds": false,
150 | "alwaysOn": false,
151 | "http20Enabled": false,
152 | "functionAppScaleLimit": 0,
153 | "minimumElasticInstanceCount": 0,
154 | "appSettings": [
155 | {
156 | "name": "ENABLE_ORYX_BUILD",
157 | "value": "false"
158 | },
159 | {
160 | "name": "SCM_DO_BUILD_DURING_DEPLOYMENT",
161 | "value": "false"
162 | },
163 | {
164 | "name": "DEPLOYMENT_SOURCE",
165 | "value": "[Concat('/home/site/repository/', parameters('Project'))]"
166 | },
167 | {
168 | "name": "azTenantId",
169 | "value": "[parameters('azTenantId')]"
170 | },
171 | {
172 | "name": "azClientId",
173 | "value": "[parameters('azClientId')]"
174 | },
175 | {
176 | "name": "azClientSecret",
177 | "value": "[parameters('azClientSecret')]"
178 | },
179 | {
180 | "name": "DidAuthority",
181 | "value": "[parameters('DidAuthority')]"
182 | },
183 | {
184 | "name": "acceptedIssuers",
185 | "value": "[parameters('DidAuthority')]"
186 | },
187 | {
188 | "name": "CredentialType",
189 | "value": "[parameters('CredentialType')]"
190 | },
191 | {
192 | "name": "CredentialManifest",
193 | "value": "[parameters('CredentialManifest')]"
194 | },
195 | {
196 | "name": "issuancePinCodeLength",
197 | "value": "4"
198 | },
199 | {
200 | "name": "photoClaimName",
201 | "value": "[parameters('PhotoClaimName')]"
202 | },
203 | {
204 | "name": "matchConfidenceThreshold",
205 | "value": "70"
206 | }
207 | ]
208 | },
209 | "scmSiteAlsoStopped": false,
210 | "clientAffinityEnabled": true,
211 | "clientCertEnabled": false,
212 | "clientCertMode": "Required",
213 | "hostNamesDisabled": false,
214 | "containerSize": 0,
215 | "dailyMemoryTimeQuota": 0,
216 | "httpsOnly": false,
217 | "redundancyMode": "None",
218 | "storageAccountRequired": false,
219 | "keyVaultReferenceIdentity": "SystemAssigned"
220 | },
221 |
222 | "resources": [
223 | {
224 | "type": "sourcecontrols",
225 | "apiVersion": "2018-02-01",
226 | "name": "web",
227 | "location": "[resourceGroup().location]",
228 | "dependsOn": [
229 | "[resourceId('Microsoft.Web/sites', parameters('webAppName'))]"
230 | ],
231 | "properties": {
232 | "repoUrl": "[parameters('repoURL')]",
233 | "branch": "[parameters('branch')]",
234 | "isManualIntegration": true
235 | }
236 | }
237 | ]
238 |
239 | },
240 |
241 | {
242 | "type": "Microsoft.Web/sites/hostNameBindings",
243 | "apiVersion": "2022-09-01",
244 | "name": "[concat(parameters('webAppName'), '/', parameters('webAppName'), '.azurewebsites.net')]",
245 | "location": "[resourceGroup().location]",
246 | "dependsOn": [
247 | "[resourceId('Microsoft.Web/sites', parameters('webAppName'))]"
248 | ],
249 | "properties": {
250 | "siteName": "[parameters('webAppName')]",
251 | "hostNameType": "Verified"
252 | }
253 | },
254 |
255 | {
256 | "type": "Microsoft.Web/sites/config",
257 | "apiVersion": "2022-09-01",
258 | "name": "[concat(parameters('webAppName'), '/web')]",
259 | "location": "[resourceGroup().location]",
260 | "dependsOn": [
261 | "[resourceId('Microsoft.Web/sites', parameters('webAppName'))]"
262 | ],
263 | "properties": {
264 | "numberOfWorkers": 1,
265 | "defaultDocuments": [
266 | "Default.htm",
267 | "Default.html",
268 | "Default.asp",
269 | "index.htm",
270 | "index.html",
271 | "iisstart.htm",
272 | "default.aspx",
273 | "index.php",
274 | "hostingstart.html"
275 | ],
276 | "netFrameworkVersion": "v4.0",
277 | "linuxFxVersion": "[variables('linuxFxVersion')]",
278 | "requestTracingEnabled": false,
279 | "remoteDebuggingEnabled": false,
280 | "httpLoggingEnabled": true,
281 | "acrUseManagedIdentityCreds": false,
282 | "logsDirectorySizeLimit": 100,
283 | "detailedErrorLoggingEnabled": false,
284 | "publishingUsername": "[concat('$', parameters('webAppName'))]",
285 | "scmType": "None",
286 | "use32BitWorkerProcess": true,
287 | "webSocketsEnabled": false,
288 | "alwaysOn": false,
289 | "managedPipelineMode": "Integrated",
290 | "appCommandLine": "[concat('cd /home/site/wwwroot && cp -r /home/site/repository/', parameters('Project'), '/* . && pip install -r requirements.txt && python app.py')]",
291 | "virtualApplications": [
292 | {
293 | "virtualPath": "/",
294 | "physicalPath": "site\\wwwroot",
295 | "preloadEnabled": false
296 | }
297 | ],
298 | "loadBalancing": "LeastRequests",
299 | "experiments": {
300 | "rampUpRules": []
301 | },
302 | "autoHealEnabled": false,
303 | "vnetRouteAllEnabled": false,
304 | "vnetPrivatePortsCount": 0,
305 | "localMySqlEnabled": false,
306 | "ipSecurityRestrictions": [
307 | {
308 | "ipAddress": "Any",
309 | "action": "Allow",
310 | "priority": 2147483647,
311 | "name": "Allow all",
312 | "description": "Allow all access"
313 | }
314 | ],
315 | "scmIpSecurityRestrictions": [
316 | {
317 | "ipAddress": "Any",
318 | "action": "Allow",
319 | "priority": 2147483647,
320 | "name": "Allow all",
321 | "description": "Allow all access"
322 | }
323 | ],
324 | "scmIpSecurityRestrictionsUseMain": false,
325 | "http20Enabled": false,
326 | "minTlsVersion": "1.2",
327 | "scmMinTlsVersion": "1.2",
328 | "ftpsState": "FtpsOnly",
329 | "preWarmedInstanceCount": 0,
330 | "elasticWebAppScaleLimit": 0,
331 | "functionsRuntimeScaleMonitoringEnabled": false,
332 | "minimumElasticInstanceCount": 0,
333 | "azureStorageAccounts": {}
334 | }
335 | }
336 |
337 | ]
338 | }
339 |
--------------------------------------------------------------------------------
/1-python-api-idtokenhint/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - python
5 | - powershell
6 | products:
7 | - Entra
8 | - Verified ID
9 | description: "A code sample demonstrating issuance and verification of verifiable credentials."
10 | urlFragment: "active-directory-verifiable-credentials-pytnon"
11 | ---
12 | # Verified ID idTokenHint Sample for Python
13 |
14 | This code sample demonstrates how to use Microsoft Entra Verified ID to issue and consume verifiable credentials.
15 |
16 | ## About this sample
17 |
18 | Welcome to Microsoft Entra Verified ID. In this sample, we'll teach you to issue your first verifiable credential: a Verified Credential Expert Card. You'll then use this card to prove to a verifier that you are a Verified Credential Expert, mastered in the art of digital credentialing. The sample uses the preview REST API which supports ID Token hints to pass a payload for the verifiable credential.
19 |
20 | ## Deploy to Azure
21 |
22 | Complete the [setup](#Setup) before deploying to Azure so that you have all the required parameters.
23 |
24 | [](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Factive-directory-verifiable-credentials-node%2Fmain%2F1-python-api-idtokenhint%2FARMTemplate%2Ftemplate.json)
25 |
26 | You will be asked to enter some parameters during deployment about your app registration and your Verified ID details. You will find these values in the admin portal.
27 |
28 | 
29 |
30 | The `photo` claim is for presentation to name the claim in the requested credential when asking for a `FaceCheck`.
31 | For issuance, the sample will use the credential manifest to determind if the credential has a photo or not.
32 | If you have a claim with a [type](https://learn.microsoft.com/en-us/entra/verified-id/rules-and-display-definitions-model#displayclaims-type) of `image/jpg;base64ur`, then the sample will add the selfie or uploaded photo to that claim during issuance.
33 |
34 | ## Test Issuance and Verification
35 |
36 | Once you have deployed this sample to Azure AppServices with a working configuration, you can issue yourself a `VerifiedCredentialExpert` credential and then test verification.
37 | This requires completing the [Verified ID onboarding and creation](https://learn.microsoft.com/en-us/entra/verified-id/verifiable-credentials-configure-issuer) of the `VerifiedCredentialExpert`.
38 | If you want to test presenting and verifying other types and credentials, follow the next section.
39 |
40 | ## Test Verification via templates
41 |
42 | The sample creates a [presentation request](https://learn.microsoft.com/en-us/entra/verified-id/get-started-request-api?tabs=http%2Cconstraints#presentation-request-example) in code based on your configuration in `setenv.cmd`.
43 | You can also use JSON templates to create other presentation requests without changing the configuration to quickly test different scenarios.
44 | This github repo provises four templates for your convenience. Right-click and copy the below links, remove `http://localhost` from the link and append it to your deployed webapp so you have a URL that looks like `.../verifier.html?template=https://...`.
45 | You can issue yourself a `VerifiedEmployee` credential at [MyAccount](https://myaccound.microsoft.com) if your organization have onboarded to Verified ID and enabled MyAccount (doc [here](https://learn.microsoft.com/en-us/entra/verified-id/verifiable-credentials-configure-tenant-quick#myaccount-available-now-to-simplify-issuance-of-workplace-credentials)).
46 |
47 | | Template | Description | Link |
48 | |------|--------|--------|
49 | | TrueIdentity | A presentation request for a [TrueIdentity](https://trueidentityinc.azurewebsites.net/) credential | [Link](http://localhost/verifier.html?template=https://raw.githubusercontent.com/Azure-Samples/active-directory-verifiable-credentials-dotnet/main/1-asp-net-core-api-idtokenhint/Templates/presentation_request_TrueIdentity.json) |
50 | | VerifiedEmployee | A presentation request for a [VerifiedEmployee](https://learn.microsoft.com/en-us/entra/verified-id/how-to-use-quickstart-verifiedemployee) credential | [Link](http://localhost/verifier.html?template=https://raw.githubusercontent.com/Azure-Samples/active-directory-verifiable-credentials-dotnet/main/1-asp-net-core-api-idtokenhint/Templates/presentation_request_VerifiedEmployee.json) |
51 | | VerifiedEmployee with FaceCheck*| A presentation request for a VerifiedEmployee credential that will perform a liveness check in the Authenticator. This requires that you have a good photo of yourself in the VerifiedEmployee credential | [Link](http://localhost/verifier.html?template=https://raw.githubusercontent.com/Azure-Samples/active-directory-verifiable-credentials-dotnet/main/1-asp-net-core-api-idtokenhint/Templates/presentation_request_VerifiedEmployee-FaceCheck.json) |
52 | | VerifiedEmployee with constraints | A presentation request for a VerifiedEmployee credential that uses a claims constraints that `jobTitle` contains the word `manager` | [Link](http://localhost/verifier.html?template=https://raw.githubusercontent.com/Azure-Samples/active-directory-verifiable-credentials-dotnet/main/1-asp-net-core-api-idtokenhint/Templates/presentation_request_VerifiedEmployee-Constraints.json) |
53 |
54 | *Note - FaceCheck is in preview. If you plan to test it, make sure you have the latest Microsoft Authenticator.
55 |
56 | ## Contents
57 |
58 | The project is divided in 2 parts, one for issuance and one for verifying a verifiable credential. Depending on the scenario you need you can remove 1 part. To verify if your environment is completely working you can use both parts to issue a `VerifiedCredentialExpert` credential and verify that as well.
59 |
60 | | Issuance | |
61 | |------|--------|
62 | | public/issuer.html|The basic webpage containing the javascript to call the APIs for issuance. Depending if you use a photo, you will see options to take a selfie or upload a stock photo of you to be issued with the credential. |
63 | | issuer.py | This is the file which contains the API called from the webpage. It calls the REST API after getting an access token through MSAL. |
64 |
65 | | Verification | |
66 | |------|--------|
67 | | public/verifier.html | The website acting as the verifier of the verifiable credential. Depending if you use a photo, you will have a checkbox that let's you create a presentation request with FaceCheck. |
68 | | verifier.py | This is the file which contains the API called from the webpage. It calls the REST API after getting an access token through MSAL and helps verifying the presented verifiable credential.
69 |
70 | | Common | |
71 | |------|--------|
72 | | public/index.html|Start page with option to continue with issuance or verification. |
73 | | public/presentation-verified.html | The webpage that displays the result of the presented VC |
74 | | public/verifiedid.requestservice.client.js|js lib that handles all the API calls to the app |
75 | | public/verifiedid.uihandler.js |js lib that handles common UI updates |
76 | | callback.py | This file handles common functions between issuance and verification. It handles callback event from Request Service API, the polling requests from the browser and generating the selfie request. |
77 |
78 | ## Setup
79 |
80 | Before you can use Verified ID you need to onboard to it. You can either onboard using the [quick setup](https://learn.microsoft.com/en-us/entra/verified-id/verifiable-credentials-configure-tenant-quick) method or the [manual setup](https://learn.microsoft.com/en-us/entra/verified-id/verifiable-credentials-configure-tenant) method. In the manual method, you use your own Azure Key Vault to store your signing key.
81 |
82 | ### Create application registration
83 | Follow the documentation for how to do [app registeration](https://learn.microsoft.com/en-us/entra/verified-id/verifiable-credentials-configure-issuer#configure-the-verifiable-credentials-app) for an app with permission to Verified ID.
84 |
85 | ## Setting up and running the sample
86 | To run the sample, clone the repository, compile & run it. It's callback endpoint must be publically reachable, and for that reason, use a tool like `ngrok` as a reverse proxy to reach your app.
87 |
88 | ```Powershell
89 | git clone https://github.com/Azure-Samples/active-directory-verifiable-credentials-python.git
90 | cd active-directory-verifiable-credentials-python\1-python-api-idtokenhint
91 | ```
92 |
93 | ### Create your credential
94 | To use the sample we need a configured Verifiable Credential in the azure portal.
95 | In the project directory CredentialFiles you will find the `VerifiedCredentialExpertDisplay.json` file and the `VerifiedCredentialExpertRules.json` file. Use these 2 files to create your own VerifiedCredentialExpert credential.
96 |
97 | If you navigate to your [Verifiable Credentials](https://portal.azure.com/#blade/Microsoft_AAD_DecentralizedIdentity/InitialMenuBlade/issuerSettingsBlade) blade in azure portal, follow the instructions how to create your first verifiable credential.
98 |
99 | You can find the instructions on how to create a Verifiable Credential in the azure portal [here](https://aka.ms/didfordev)
100 |
101 | ### Setting app's configuration
102 | The sample uses environment variables for app configuration. The files [setenv.cmd](setenv.cmd) and [setenv.sh](setenv.sh) contains a template for setting the required environment variables before you run the app. You need to update the files with the appropriate values.
103 |
104 | ```Dos
105 | @echo off
106 | set azTenantId=
107 | set azClientId=
108 | set azClientSecret=
109 | set DidAuthority=did:web:...your-domain....com
110 | set clientName=Python Verified ID sample
111 | set purpose=To prove you are an Verified ID expert
112 | set CredentialManifest=https://verifiedid.did.msidentity.com/v1.0/tenants/...etc...
113 | set CredentialType=VerifiedCredentialExpert
114 | set acceptedIssuers=%DidAuthority%
115 | set issuancePinCodeLength=4
116 | set sourcePhotoClaimName=
117 | set matchConfidenceThreshold=70
118 | ```
119 |
120 | | Env var | Source | Description |
121 | |------|--------|--------|
122 | | azTenantId | Directory (tenant) id in AppReg blade | Identifies your Entra ID tenant |
123 | | azClientId | Application (client) id in AppReg blade | Identifies your app |
124 | | azClientSecret | Certificates & secrets in AppReg blade | app's client secret |
125 | | DidAuthority | Verified ID blade | Identifies your Verified ID authority |
126 | | clientName | file | Descriptive name that displays in the Authenticator |
127 | | purpose | file | Descriptive purpose that displays in the Authenticator |
128 | | CredentialManifest | verified ID blade | URL to manifest for credential. Used during issuance. |
129 | | CredentialType | Verified ID blade | type name of credential. Used during presentation to ask for type of VC |
130 | | acceptedIssuers | file | ;-separated list of DIDs of issuers you accept in your presentation request |
131 | | issuancePinCodeLength | file | Value 0-6, where 0 means no pin code |
132 | | sourcePhotoClaimName | file | Name of the photo claim if the presentation request is using FaceCheck |
133 | | matchConfidenceThreshold | file | Confidence score threshold for FaceCheck. Dault is 70. |
134 |
135 | ### API Payloads
136 | The sample app doesn't require that you specify JSON payloads in files anymore as it generates the required JSON internally. If you still prefer to use the JSON payloads, you can pass them on the command line and the config values will merge with whatever values are set in environment variables.
137 |
138 | ## Running the sample
139 |
140 | In order to build & run the sample, you need to have the [python](https://www.python.org/downloads/) installed locally.
141 |
142 | 1. After you have edited either of the files [setenv.cmd](setenv.cmd) or [setenv.sh](setenv.sh), depending on your OS, start the python app by running this in the command prompt
143 |
144 | ```Powershell
145 | pip install -r requirements.txt
146 | .\setenv.cmd
147 | python app.py
148 | ```
149 |
150 | 1. Using a different command prompt, run ngrok to set up a URL on 8080. You can install ngrok globally from this [link](https://ngrok.com/download).
151 | ```Powershell
152 | ngrok http 8080
153 | ```
154 |
155 | 1. Open the HTTPS URL generated by ngrok.
156 | 
157 | The sample dynamically copies the hostname to be part of the callback URL, this way Verified ID's Request Service can reach your sample web application to execute the callback method.
158 |
159 | 1. Select Issue Credential
160 |
161 | 1. In Authenticator, scan the QR code.
162 | > If this is the first time you are using Verifiable Credentials the Credentials page with the Scan QR button is hidden. You can use the `add account` button. Select `other` and scan the QR code, this will enable the preview of Verifiable Credentials in Authenticator.
163 | 1. Select **Add**.
164 |
165 | ## Verify the verifiable credential by using the sample app
166 | 1. Navigate back and click on the Verify Credential button
167 | 2. Click Verify Credential button
168 | 3. Scan the QR code
169 | 4. select the VerifiedCredentialExpert credential and click share
170 | 5. You should see the result presented on the screen.
171 |
172 |
173 | ## Troubleshooting
174 |
175 | ### Did you forget to provide admin consent? This is needed for confidential apps
176 | If you get an error when calling the API `Insufficient privileges to complete the operation.`, this is because the tenant administrator has not granted permissions
177 | to the application. See step 6 of 'Register the client app' above.
178 |
179 | You will typically see, on the output window, something like the following:
180 |
181 | ```Json
182 | Failed to call the Web Api: Forbidden
183 | Content: {
184 | "error": {
185 | "code": "Authorization_RequestDenied",
186 | "message": "Insufficient privileges to complete the operation.",
187 | "innerError": {
188 | "request-id": "",
189 | "date": ""
190 | }
191 | }
192 | }
193 | ```
194 |
195 | ### Understanding what's going on
196 | As a first source of information, the Python sample will trace output into the console window of all HTTP calls it receives. Then a good tip is to use Edge/Chrome/Firefox dev tools functionality found under F12 and watch the Network tab for traffic going from the browser to the Node app.
197 |
198 | ## Best practices
199 | When deploying applications which need client credentials and use secrets or certificates the more secure practice is to use certificates. If you are hosting your application on azure make sure you check how to deploy managed identities. This takes away the management and risks of secrets in your application.
200 | You can find more information here:
201 | - [Integrate a daemon app with Key Vault and MSI](https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/tree/master/3-Using-KeyVault)
202 |
203 |
204 | ## More information
205 |
206 | For more information, see MSAL.NET's conceptual documentation:
207 |
208 | - [Quickstart: Register an application with the Microsoft identity platform](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app)
209 | - [Quickstart: Configure a client application to access web APIs](https://docs.microsoft.com/azure/active-directory/develop/quickstart-configure-app-access-web-apis)
210 | - [Acquiring a token for an application with client credential flows](https://aka.ms/msal-net-client-credentials)
211 |
--------------------------------------------------------------------------------
/1-python-api-idtokenhint/public/qrcode.min.js:
--------------------------------------------------------------------------------
1 | var QRCode;!function(){function t(t){this.mode=r.MODE_8BIT_BYTE,this.data=t,this.parsedData=[];for(var e=0,o=this.data.length;e65536?(i[0]=240|(1835008&n)>>>18,i[1]=128|(258048&n)>>>12,i[2]=128|(4032&n)>>>6,i[3]=128|63&n):n>2048?(i[0]=224|(61440&n)>>>12,i[1]=128|(4032&n)>>>6,i[2]=128|63&n):n>128?(i[0]=192|(1984&n)>>>6,i[1]=128|63&n):i[0]=n,this.parsedData.push(i)}this.parsedData=Array.prototype.concat.apply([],this.parsedData),this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function e(t,e){this.typeNumber=t,this.errorCorrectLevel=e,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}t.prototype={getLength:function(t){return this.parsedData.length},write:function(t){for(var e=0,r=this.parsedData.length;e=7&&this.setupTypeNumber(t),null==this.dataCache&&(this.dataCache=e.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,r)},setupPositionProbePattern:function(t,e){for(var r=-1;r<=7;r++)if(!(t+r<=-1||this.moduleCount<=t+r))for(var o=-1;o<=7;o++)e+o<=-1||this.moduleCount<=e+o||(this.modules[t+r][e+o]=0<=r&&r<=6&&(0==o||6==o)||0<=o&&o<=6&&(0==r||6==r)||2<=r&&r<=4&&2<=o&&o<=4)},getBestMaskPattern:function(){for(var t=0,e=0,r=0;r<8;r++){this.makeImpl(!0,r);var o=g.getLostPoint(this);(0==r||t>o)&&(t=o,e=r)}return e},createMovieClip:function(t,e,r){var o=t.createEmptyMovieClip(e,r);this.make();for(var i=0;i>r&1);this.modules[Math.floor(r/3)][r%3+this.moduleCount-8-3]=o}for(r=0;r<18;r++){o=!t&&1==(e>>r&1);this.modules[r%3+this.moduleCount-8-3][Math.floor(r/3)]=o}},setupTypeInfo:function(t,e){for(var r=this.errorCorrectLevel<<3|e,o=g.getBCHTypeInfo(r),i=0;i<15;i++){var n=!t&&1==(o>>i&1);i<6?this.modules[i][8]=n:i<8?this.modules[i+1][8]=n:this.modules[this.moduleCount-15+i][8]=n}for(i=0;i<15;i++){n=!t&&1==(o>>i&1);i<8?this.modules[8][this.moduleCount-i-1]=n:i<9?this.modules[8][15-i-1+1]=n:this.modules[8][15-i-1]=n}this.modules[this.moduleCount-8][8]=!t},mapData:function(t,e){for(var r=-1,o=this.moduleCount-1,i=7,n=0,a=this.moduleCount-1;a>0;a-=2)for(6==a&&a--;;){for(var s=0;s<2;s++)if(null==this.modules[o][a-s]){var h=!1;n>>i&1)),g.getMask(e,o,a-s)&&(h=!h),this.modules[o][a-s]=h,-1==--i&&(n++,i=7)}if((o+=r)<0||this.moduleCount<=o){o-=r,r=-r;break}}}},e.PAD0=236,e.PAD1=17,e.createData=function(t,r,o){for(var i=m.getRSBlocks(t,r),n=new _,a=0;a8*h)throw new Error("code length overflow. ("+n.getLengthInBits()+">"+8*h+")");for(n.getLengthInBits()+4<=8*h&&n.put(0,4);n.getLengthInBits()%8!=0;)n.putBit(!1);for(;!(n.getLengthInBits()>=8*h||(n.put(e.PAD0,8),n.getLengthInBits()>=8*h));)n.put(e.PAD1,8);return e.createBytes(n,i)},e.createBytes=function(t,e){for(var r=0,o=0,i=0,n=new Array(e.length),a=new Array(e.length),s=0;s=0?d.get(c):0}}var m=0;for(u=0;u=0;)e^=g.G15<=0;)e^=g.G18<>>=1;return e},getPatternPosition:function(t){return g.PATTERN_POSITION_TABLE[t-1]},getMask:function(t,e,r){switch(t){case i:return(e+r)%2==0;case n:return e%2==0;case a:return r%3==0;case s:return(e+r)%3==0;case h:return(Math.floor(e/2)+Math.floor(r/3))%2==0;case l:return e*r%2+e*r%3==0;case u:return(e*r%2+e*r%3)%2==0;case f:return(e*r%3+(e+r)%2)%2==0;default:throw new Error("bad maskPattern:"+t)}},getErrorCorrectPolynomial:function(t){for(var e=new p([1],0),r=0;r5&&(r+=3+n-5)}for(o=0;o=256;)t-=255;return d.EXP_TABLE[t]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},c=0;c<8;c++)d.EXP_TABLE[c]=1<>>7-t%8&1)},put:function(t,e){for(var r=0;r>>e-r-1&1))},getLengthInBits:function(){return this.length},putBit:function(t){var e=Math.floor(this.length/8);this.buffer.length<=e&&this.buffer.push(0),t&&(this.buffer[e]|=128>>>this.length%8),this.length++}};var v=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]];function C(){var t=!1,e=navigator.userAgent;if(/android/i.test(e)){t=!0;var r=e.toString().match(/android ([0-9]\.[0-9])/i);r&&r[1]&&(t=parseFloat(r[1]))}return t}var w=function(){var t=function(t,e){this._el=t,this._htOption=e};return t.prototype.draw=function(t){var e=this._htOption,r=this._el,o=t.getModuleCount();Math.floor(e.width/o),Math.floor(e.height/o);function i(t,e){var r=document.createElementNS("http://www.w3.org/2000/svg",t);for(var o in e)e.hasOwnProperty(o)&&r.setAttribute(o,e[o]);return r}this.clear();var n=i("svg",{viewBox:"0 0 "+String(o)+" "+String(o),width:"100%",height:"100%",fill:e.colorLight});n.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),r.appendChild(n),n.appendChild(i("rect",{fill:e.colorLight,width:"100%",height:"100%"})),n.appendChild(i("rect",{fill:e.colorDark,width:"1",height:"1",id:"template"}));for(var a=0;a'],s=0;s");for(var h=0;h');a.push("")}a.push(""),r.innerHTML=a.join("");var l=r.childNodes[0],u=(e.width-l.offsetWidth)/2,f=(e.height-l.offsetHeight)/2;u>0&&f>0&&(l.style.margin=f+"px "+u+"px")},t.prototype.clear=function(){this._el.innerHTML=""},t}():function(){function t(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}if(this._android&&this._android<=2.1){var e=1/window.devicePixelRatio,r=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(t,o,i,n,a,s,h,l,u){if("nodeName"in t&&/img/i.test(t.nodeName))for(var f=arguments.length-1;f>=1;f--)arguments[f]=arguments[f]*e;else void 0===l&&(arguments[1]*=e,arguments[2]*=e,arguments[3]*=e,arguments[4]*=e);r.apply(this,arguments)}}var o=function(t,e){this._bIsPainted=!1,this._android=C(),this._htOption=e,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=e.width,this._elCanvas.height=e.height,t.appendChild(this._elCanvas),this._el=t,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.alt="Scan me!",this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return o.prototype.draw=function(t){var e=this._elImage,r=this._oContext,o=this._htOption,i=t.getModuleCount(),n=o.width/i,a=o.height/i,s=Math.round(n),h=Math.round(a);e.style.display="none",this.clear();for(var l=0;lv.length)throw new Error("Too long data");return r}(QRCode=function(t,e){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:o.H},"string"==typeof e&&(e={text:e}),e)for(var r in e)this._htOption[r]=e[r];"string"==typeof t&&(t=document.getElementById(t)),this._htOption.useSVG&&(D=w),this._android=C(),this._el=t,this._oQRCode=null,this._oDrawing=new D(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)}).prototype.makeCode=function(t){this._oQRCode=new e(A(t,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(t),this._oQRCode.make(),this._el.title=t,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=o}(),"undefined"!=typeof module&&(module.exports=QRCode);
2 |
--------------------------------------------------------------------------------
/ReadmeFiles/SampleArchitectureOverview.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
441 |
--------------------------------------------------------------------------------
/1-python-api-idtokenhint/ReadmeFiles/SampleArchitectureOverview.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
441 |
--------------------------------------------------------------------------------