This repository provides a playground to experiment with service to service communication between custom services.
The repository contains two small REST API services, implemented in ASP.NET Core:
- CodeRepositoryService
- Provides APIs to manage pseudo code repositories
- CiService
- Provides APIs to create pseudo jobs for repositories, served by CodeRepository service
- Communicates either with an app-token, acquired by
client_credentialsflow, or with an user-token, acquired byon-behalf-offlow
The repository can be used to demo four authentication flows:
- Authorization code flow using PKCE
- Using swagger-ui
- Client credentials flow
- Using terraform-generated
ci-service.client_credentials.for.code-repository-service.shscript and swagger-ui - Alternatively implicitly by creating a CiService job, which uses the .NET
Microsoft.Identity.Web.DownstreamApiLibrary
- Using terraform-generated
- On-behalf-of flow
- Using terraform-generated
ci-service.device-code.and.on-behalf-of.flow.for.code-repository-service.shscript and swagger-ui - Alternatively implicitly using the .NET
Microsoft.Identity.Web.DownstreamApiLibrary
- Using terraform-generated
- Device code flow
- Using terraform-generated
ci-service.device-code.and.on-behalf-of.flow.for.code-repository-service.shscript and swagger-ui
- Using terraform-generated
- Install Azure CLI, Terraform, Docker
- Login to Azure Tenant with Azure CLI:
az login --tenant "${YOUR_TENANT_ID}"- Nothing bad will happen if you are signed in to a different tenant by accident. The follwing scripts will simply fail to execute.
- Create a
config.shfile, similar to theconfig.example.sh. - Execute
terraform_plan.shin the project root directory to inspect planned changes in the Azure tenant. - Execute
setup_and_start.shin the project root directory.- Provisions example App registrations via terraform in target Entra ID directory
- Creates
appsettings.Compose.jsoninapps/CiServiceandapps/CodeRepositoryServicefor docker-compose environment - Creates
appsettings.Development.jsoninapps/CiServiceandapps/CodeRepositoryServicefor local debugging - Starts a swagger-ui on http://localhost:8080
- Builds and starts CiService and CodeRepositoryService in docker-compose environment
- Keeps running and prints logs of
swagger-ui,ci-serviceandcode-repository-service
- Open swagger-ui in browser on http://localhost:8080
- Select
CodeRepositorydefinition (should be the default) - Authorize for
code-repository-serviceapplication- Click
Authorizebutton to openAvailable authorizationsdialog - Scroll to
UserAuthenticationform - Select
{app-id}/.defaultscope. - Copy
{app-id}into theclient_idfield - Click
AuthorizeonAvailable authorizationsdialog - Accept consent form for
code-repository-serviceapplication - Click
CloseonAvailable authorizationsdialog
- Click
- Create
testrepository- Click
Try it outonPOST /repositories - Enter
testasrepositoryName - Click
Executebutton
- Click
- Inspect logs of
code-repository-service-1to see the Bearer token- Decode Bearer token. E.g. via https://jwt.io/
-
{ "aud": "{CODE_REPOSITORY_CLIENT_ID}", // Audience: Client ID of the code repository server application. Other applications must not accept this token. "iss": "https://login.microsoftonline.com/{TENANT_ID}/v2.0", // Issuer: Authorization server which issued this token. Is trusted by the code repository server. "azp": "{CODE_REPOSITORY_CLIENT_ID}", // Authorized Party: Client ID of the code repository server application. "name": "{user_display_name}", "oid": "{user_principal_object_id_in_entra_id}", "preferred_username": "{preferred_username}", "scp": "UserImpersonation.ReadWrite.All", // Scopes: Token authorizes to perform read and write operations on behalf of the user. This scope is only valid for the specfic audience (in this case the code repository service)! "sub": "{application_scoped_user_id_string}", "tid": "{TENANT_ID}", [...] }
- Create code resource via
PUT /repositories/{repositoryName}/codeendpoint for thetestrepository and with any content
- Select
CiServicedefinition in swagger-ui - Authorize for
ci-serviceapplication- Click
Authorizebutton to openAvailable authorizationsdialog - Scroll to
UserAuthenticationform - Select
{app-id}/.defaultscope. - Copy
{app-id}into theclient_idfield - Click
AuthorizeonAvailable authorizationsdialog - Accept consent form for
ci-serviceapplication - Click
CloseonAvailable authorizationsdialog
- Click
- Create job for
testrepository with any command and withimpersonateUser=false - Inspect logs of
ci-service-1to see the Bearer token- Decode Bearer token. E.g. via https://jwt.io/
-
{ "aud": "{CI_SERVICE_CLIENT_ID}", // Audience: Client ID of the ci service application. Other applications must not accept this token. "iss": "https://login.microsoftonline.com/{TENANT_ID}/v2.0", // Issuer: Authorization server which issued this token. Is trusted by the ci service. "azp": "{CI_SERVICE_CLIENT_ID}", // Authorized Party: Client ID of the ci service application. "name": "{user_display_name}", "oid": "{user_principal_object_id_in_entra_id}", "preferred_username": "{preferred_username}", "scp": "UserImpersonation.ReadWrite.All", // Scopes: Token authorizes to perform read and write operations on behalf of the user. This scope is only valid for the specfic audience (in this case the ci service)! "sub": "{application_scoped_user_id_string}", "tid": "{TENANT_ID}", }
- Inspect logs of
code-repository-service-1to see the Bearer token- Decode Bearer token. E.g. via https://jwt.io/
-
{ "aud": "{CODE_REPOSITORY_CLIENT_ID}", // Audience: Client ID of the code repository server application. Other applications must not accept this token. "iss": "https://login.microsoftonline.com/{TENANT_ID}/v2.0", "azp": "{CI_SERVICE_CLIENT_ID}", // Authorized Party: Client ID of the ci service application. "oid": "{ci_service_principal_object_id_in_entra_id}", "roles": [ "Repositories.Code.Read.All" // ci-service has the code-repsitory-service app role "Repositories.Code.Read.All" assigned. Therefore it is allowed to read the repository code of any user. ], "sub": "{ci_service_principal_object_id_in_entra_id}", "tid": "{TENANT_ID}", [...] }
Create Job for test repository, authenticating to CodeRepositoryService on-behalf of the user via a user token
- Create job for
testrepository with any command and withimpersonateUser=true - Inspect logs of
ci-service-1to see the Bearer token- Should be still the same user token like before
- Inspect logs of
code-repository-service-1to see the Bearer token- Decode Bearer token. E.g. via https://jwt.io/
-
{ "aud": "{CODE_REPOSITORY_CLIENT_ID}", // Audience: Client ID of the code repository server application. Other applications must not accept this token. "iss": "https://login.microsoftonline.com/{TENANT_ID}/v2.0", "azp": "{CI_SERVICE_CLIENT_ID}", // Authorized Party: Client ID of the ci service application. "name": "{user_display_name}", "oid": "{user_principal_object_id_in_entra_id}", "preferred_username": "{preferred_username}", "scp": "UserImpersonation.Repositories.Code.Read.All", // Scopes: Token authorizes to read repository code on behalf of the user. This scope is only valid for the specfic audience (in this case the code repository service)! "sub": "{application_scoped_user_id_string}", "tid": "{TENANT_ID}", [...] }


