diff --git a/samples/entra-secured-crud-api/.devproxy/customers-api.json b/samples/entra-secured-crud-api/.devproxy/customers-api.json new file mode 100644 index 0000000..4a51b79 --- /dev/null +++ b/samples/entra-secured-crud-api/.devproxy/customers-api.json @@ -0,0 +1,62 @@ +{ + "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.1.0-beta.3/crudapiplugin.apifile.schema.json", + "baseUrl": "https://api.contoso.com/v1/customers", + "dataFile": "customers-data.json", + "auth": "entra", + "entraAuthConfig": { + "audience": "https://api.contoso.com", + "issuer": "https://login.microsoftonline.com/contoso.com" + }, + "actions": [ + { + "action": "getAll", + "auth": "entra", + "entraAuthConfig": { + "scopes": ["api://contoso.com/customer.read"] + } + }, + { + "action": "getOne", + "url": "/{customer-id}", + "query": "$.[?(@.id == {customer-id})]", + "auth": "entra", + "entraAuthConfig": { + "scopes": ["api://contoso.com/customer.read"] + } + }, + { + "action": "create", + "auth": "entra", + "entraAuthConfig": { + "scopes": ["api://contoso.com/customer.write"] + } + }, + { + "action": "merge", + "url": "/{customer-id}", + "query": "$.[?(@.id == {customer-id})]", + "auth": "entra", + "entraAuthConfig": { + "scopes": ["api://contoso.com/customer.write"] + } + }, + { + "action": "update", + "url": "/{customer-id}", + "query": "$.[?(@.id == {customer-id})]", + "auth": "entra", + "entraAuthConfig": { + "scopes": ["api://contoso.com/customer.write"] + } + }, + { + "action": "delete", + "url": "/{customer-id}", + "query": "$.[?(@.id == {customer-id})]", + "auth": "entra", + "entraAuthConfig": { + "scopes": ["api://contoso.com/customer.write"] + } + } + ] +} diff --git a/samples/entra-secured-crud-api/.devproxy/customers-data.json b/samples/entra-secured-crud-api/.devproxy/customers-data.json new file mode 100644 index 0000000..ce59ea4 --- /dev/null +++ b/samples/entra-secured-crud-api/.devproxy/customers-data.json @@ -0,0 +1,47 @@ +[ + { + "id": 1, + "name": "Contoso Ltd", + "email": "contact@contoso.com", + "phone": "+1-555-0100", + "address": "123 Innovation Drive, Seattle, WA 98101", + "industry": "Technology", + "createdAt": "2024-01-15T10:30:00Z" + }, + { + "id": 2, + "name": "Fabrikam Inc", + "email": "info@fabrikam.com", + "phone": "+1-555-0200", + "address": "456 Enterprise Blvd, Redmond, WA 98052", + "industry": "Manufacturing", + "createdAt": "2024-02-20T14:45:00Z" + }, + { + "id": 3, + "name": "Tailspin Toys", + "email": "hello@tailspintoys.com", + "phone": "+1-555-0300", + "address": "789 Retail Lane, Bellevue, WA 98004", + "industry": "Retail", + "createdAt": "2024-03-10T09:15:00Z" + }, + { + "id": 4, + "name": "Northwind Traders", + "email": "sales@northwindtraders.com", + "phone": "+1-555-0400", + "address": "321 Commerce Street, Portland, OR 97201", + "industry": "Wholesale", + "createdAt": "2024-04-05T16:20:00Z" + }, + { + "id": 5, + "name": "Adventure Works", + "email": "support@adventureworks.com", + "phone": "+1-555-0500", + "address": "654 Outdoor Ave, Denver, CO 80202", + "industry": "Sports & Recreation", + "createdAt": "2024-05-12T11:00:00Z" + } +] diff --git a/samples/entra-secured-crud-api/.devproxy/devproxyrc.json b/samples/entra-secured-crud-api/.devproxy/devproxyrc.json new file mode 100644 index 0000000..d6d8f03 --- /dev/null +++ b/samples/entra-secured-crud-api/.devproxy/devproxyrc.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.1.0-beta.3/rc.schema.json", + "plugins": [ + { + "name": "CrudApiPlugin", + "enabled": true, + "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll", + "configSection": "customersApi" + } + ], + "urlsToWatch": [ + "https://api.contoso.com/*" + ], + "customersApi": { + "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v2.1.0-beta.3/crudapiplugin.schema.json", + "apiFile": "customers-api.json" + } +} diff --git a/samples/entra-secured-crud-api/README.md b/samples/entra-secured-crud-api/README.md new file mode 100644 index 0000000..b9e442d --- /dev/null +++ b/samples/entra-secured-crud-api/README.md @@ -0,0 +1,113 @@ +# CRUD API secured with Microsoft Entra + +## Summary + +This sample demonstrates how to simulate a CRUD API secured with Microsoft Entra authentication using Dev Proxy. It includes a demo web application that shows how to: + +- Authenticate with Microsoft Entra using different scopes +- Call CRUD API endpoints with Bearer token authorization +- Handle different permission levels (read vs write operations) + +Use this sample to build frontend applications before the backend API exists, with real Microsoft Entra authentication flow. + + + +## Compatibility + + + +## Contributors + +- [Waldek Mastykarz](https://github.com/waldekmastykarz) + +## Version history + +Version|Date|Comments +-------|----|-------- +1.0|January 16, 2026|Initial release + +## Prerequisites + +- [Dev Proxy](https://aka.ms/devproxy) +- [Node.js LTS](https://nodejs.org) (for http-server) + +## Minimal path to awesome + +- Clone this repository (or [download this solution as a .ZIP file](https://pnp.github.io/download-partial/?url=https://github.com/pnp/proxy-samples/tree/main/samples/entra-secured-crud-api) then unzip it) +- Navigate to the sample folder: `cd samples/entra-secured-crud-api` +- Run `npm install` to install dependencies +- Run `npm start` to start Dev Proxy and the web server +- Open http://localhost:3000 in your browser +- Select a token scope (read, write, or both) and click **Generate Token** +- Click the API operation buttons to see the responses + +## Features + +This sample demonstrates Microsoft Entra secured APIs using the CrudApiPlugin. + +### API Endpoints + +The API is exposed at `https://api.contoso.com/v1/customers` with the following operations: + +Endpoint|Method|Required Scope|Description +--------|------|--------------|------- +`/v1/customers`|`GET`|`customer.read`|Get all customers +`/v1/customers/{id}`|`GET`|`customer.read`|Get a customer by ID +`/v1/customers`|`POST`|`customer.write`|Create a new customer +`/v1/customers/{id}`|`PATCH`|`customer.write`|Update a customer +`/v1/customers/{id}`|`PUT`|`customer.write`|Replace a customer +`/v1/customers/{id}`|`DELETE`|`customer.write`|Delete a customer + +### Authentication Configuration + +The sample uses the following Microsoft Entra configuration: + +Property|Value +--------|----- +Audience|`https://api.contoso.com` +Issuer|`https://login.microsoftonline.com/contoso.com` +Read Scope|`api://contoso.com/customer.read` +Write Scope|`api://contoso.com/customer.write` + +### Demo App Features + +The included web application demonstrates: + +- **Token generation** - Generate JWT tokens using Dev Proxy's token API with different scopes +- **Scope selection** - Choose between read-only, write-only, or both scopes +- **CRUD operations** - Test all API operations (GET, POST, PATCH, DELETE) +- **Response visualization** - See full API responses including headers and status codes + +### Customizing Token Validation + +To enable full token validation (for use with real Microsoft Entra tokens), update the `.devproxy/customers-api.json` file to add validation options: + +```json +{ + "entraAuthConfig": { + "audience": "https://api.contoso.com", + "issuer": "https://login.microsoftonline.com/YOUR-TENANT-ID/v2.0", + "validateSigningKey": true, + "validateLifetime": true + } +} +``` + +> [!NOTE] +> Update the `audience` and `issuer` values to match your actual Microsoft Entra app registration when testing with real tokens. + +## Help + +We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues. + +You can try looking at [issues related to this sample](https://github.com/pnp/proxy-samples/issues?q=label%3A%22sample%3A%20entra-secured-crud-api%22) to see if anybody else is having the same issues. + +If you encounter any issues using this sample, [create a new issue](https://github.com/pnp/proxy-samples/issues/new). + +Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/proxy-samples/issues/new). + +## Disclaimer + +**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.** + + diff --git a/samples/entra-secured-crud-api/assets/sample.json b/samples/entra-secured-crud-api/assets/sample.json new file mode 100644 index 0000000..410a5a5 --- /dev/null +++ b/samples/entra-secured-crud-api/assets/sample.json @@ -0,0 +1,77 @@ +[ + { + "name": "pnp-devproxy-entra-secured-crud-api", + "source": "pnp", + "title": "CRUD API secured with Microsoft Entra", + "shortDescription": "This sample demonstrates how to simulate a CRUD API secured with Microsoft Entra authentication. It includes a demo web application that shows authentication with different scopes and CRUD operations with Bearer token authorization.", + "url": "https://github.com/pnp/proxy-samples/tree/main/samples/entra-secured-crud-api", + "downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/proxy-samples/tree/main/samples/entra-secured-crud-api", + "longDescription": [ + "This sample demonstrates how to simulate a CRUD API secured with Microsoft Entra authentication. It includes a demo web application that shows authentication with different scopes and CRUD operations with Bearer token authorization." + ], + "creationDateTime": "2026-01-16", + "updateDateTime": "2026-01-16", + "products": [ + "Dev Proxy" + ], + "metadata": [ + { + "key": "SAMPLE ID", + "value": "entra-secured-crud-api" + }, + { + "key": "PRESET", + "value": "No" + }, + { + "key": "MOCKS", + "value": "Yes" + }, + { + "key": "PLUGIN", + "value": "No" + }, + { + "key": "PROXY VERSION", + "value": "v2.1.0-beta.3" + } + ], + "thumbnails": [ + { + "type": "image", + "order": 100, + "url": "https://github.com/pnp/proxy-samples/raw/main/samples/entra-secured-crud-api/assets/screenshot.png", + "alt": "Customer Manager demo app showing Entra secured CRUD API" + } + ], + "authors": [ + { + "gitHubAccount": "waldekmastykarz", + "pictureUrl": "https://github.com/waldekmastykarz.png", + "name": "Waldek Mastykarz" + } + ], + "references": [ + { + "name": "Simulate a CRUD API secured with Microsoft Entra", + "description": "Learn how to use Dev Proxy to simulate a CRUD API secured with Microsoft Entra authentication.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/how-to/simulate-crud-api-entra" + }, + { + "name": "CrudApiPlugin", + "description": "Technical reference for the CrudApiPlugin that simulates CRUD APIs.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/technical-reference/crudapiplugin" + }, + { + "name": "Get started with the Dev Proxy", + "description": "The tutorial will introduce you to the Dev Proxy and show you how to use its features.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/get-started" + }, + { + "name": "Use preset configurations", + "description": "Instructions on how to configure the Dev Proxy to use a different configuration file.", + "url": "https://learn.microsoft.com/microsoft-cloud/dev/dev-proxy/how-to/use-preset-configurations" + } + ] + } +] diff --git a/samples/entra-secured-crud-api/assets/screenshot.png b/samples/entra-secured-crud-api/assets/screenshot.png new file mode 100644 index 0000000..2c817d4 Binary files /dev/null and b/samples/entra-secured-crud-api/assets/screenshot.png differ diff --git a/samples/entra-secured-crud-api/index.html b/samples/entra-secured-crud-api/index.html new file mode 100644 index 0000000..6fd11d7 --- /dev/null +++ b/samples/entra-secured-crud-api/index.html @@ -0,0 +1,439 @@ + + +
+ + +Demo app for Microsoft Entra secured CRUD API with Dev Proxy
+ +