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_credentials
flow, or with an user-token, acquired byon-behalf-of
flow
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.sh
script and swagger-ui - Alternatively implicitly by creating a CiService job, which uses the .NET
Microsoft.Identity.Web.DownstreamApi
Library
- Using terraform-generated
- On-behalf-of flow
- Using terraform-generated
ci-service.device-code.and.on-behalf-of.flow.for.code-repository-service.sh
script and swagger-ui - Alternatively implicitly using the .NET
Microsoft.Identity.Web.DownstreamApi
Library
- Using terraform-generated
- Device code flow
- Using terraform-generated
ci-service.device-code.and.on-behalf-of.flow.for.code-repository-service.sh
script 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.sh
file, similar to theconfig.example.sh
. - Execute
terraform_plan.sh
in the project root directory to inspect planned changes in the Azure tenant. - Execute
setup_and_start.sh
in the project root directory.- Provisions example App registrations via terraform in target Entra ID directory
- Creates
appsettings.Compose.json
inapps/CiService
andapps/CodeRepositoryService
for docker-compose environment - Creates
appsettings.Development.json
inapps/CiService
andapps/CodeRepositoryService
for 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-service
andcode-repository-service
- Open swagger-ui in browser on http://localhost:8080
- Select
CodeRepository
definition (should be the default) - Authorize for
code-repository-service
application- Click
Authorize
button to openAvailable authorizations
dialog - Scroll to
UserAuthentication
form - Select
{app-id}/.default
scope. - Copy
{app-id}
into theclient_id
field - Click
Authorize
onAvailable authorizations
dialog - Accept consent form for
code-repository-service
application - Click
Close
onAvailable authorizations
dialog
- Click
- Create
test
repository- Click
Try it out
onPOST /repositories
- Enter
test
asrepositoryName
- Click
Execute
button
- Click
- Inspect logs of
code-repository-service-1
to 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}/code
endpoint for thetest
repository and with any content
- Select
CiService
definition in swagger-ui - Authorize for
ci-service
application- Click
Authorize
button to openAvailable authorizations
dialog - Scroll to
UserAuthentication
form - Select
{app-id}/.default
scope. - Copy
{app-id}
into theclient_id
field - Click
Authorize
onAvailable authorizations
dialog - Accept consent form for
ci-service
application - Click
Close
onAvailable authorizations
dialog
- Click
- Create job for
test
repository with any command and withimpersonateUser=false
- Inspect logs of
ci-service-1
to 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-1
to 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}", [...] }