Developer’s guide to auth with Azure Resource Manager API

If you’ve read past the title, into this paragraph – it is likely that you are a software developer who wishes to integrate an app with Microsoft Azure. Or specifically, you wish to manage your customer’s Azure resources, and are wondering how to auth with Azure Resource Manager APIs. You’re at the right place – read on.

Your app can access Azure Management APIs in couple of ways:

  1. User + app access: in this method, the application accesses Azure Management APIs on behalf of the signed-in user. Applications that solely deal with “interactive management” of Azure resources should pick this method. This method can be used by Web applications as well as command-line tools.
  2. App-only access: in this method, the application’s identity is granted direct access to Azure resources, and the application accesses Azure Management APIs using its own identity. Daemon services and scheduled jobs that need long-term “offline access” to Azure should pick this method. It is worth noting that the Classic Management APIs of Azure aka Azure Service Management APIs support certificate based auth to address app-only access scenario – where the application is given a management certificate that has full access to the Azure subscription. The new Azure Resource Manager APIs do not support management certificates, instead app-only access is enabled using Azure AD based application identities and OAuth.

This post will give a step-by-step description of how to create an app that employs both these auth methods.

We’ll build a web application that will sign-in an Azure user –> query Azure Management APIs on behalf of the user (user + app access), to get a list of Azure subscriptions that the user owns –> allow the user to “connect” subscriptions to the app (grant direct access on the subscription to the identity of the application) –> access Azure Management APIs as the application to perform offline operations (app-only access).

Here’s the end-to-end flow of the web application that we shall write.

ARM Auth - Swim Lane

The experience of the end-user will look like this:

 ARM Auth - Sample App Ux 1  ArrowRight.png  ARM Auth - Sample App Ux 2  ArrowRight.png  ARM Auth - Sample App Ux 3
 ArrowDown.png
 ARM Auth - Sample App Ux 6  ArrowLeft.png  ARM Auth - Sample App Ux 5  ArrowLeft.png  ARM Auth - Sample App Ux 4

1. Register your Application with Azure Active Directory

You shall begin by registering you web app with Azure Active Directory. The app registration creates a central identity for your app in Azure AD. It holds basic information about your application like OAuth Client ID, Reply URLs and credentials that your application will use to authenticate and access Azure Resource Manager APIs. The app registration also records the various delegated permissions that your applications needs when accessing Microsoft APIs on behalf of the user. This topic provides more details on Azure AD app registration.

1.1 Sign-up for Azure (subscription)

If you haven’t signed up for Azure yet, do so now. I recommend signing up using your work account (if your company isn’t already using Azure AD/Office 365 you can create an organizational account as part of sign-up). If you’ve already signed up using a personal Microsoft Account aka Live Id – you can continue using it for this integration – however you should consider transferring the Azure account/subscription to a work account later.

1.2 Register Web Application

Sign-in to the Azure Management Portal and navigate to the Azure AD node in the left pane. Select the directory in which you wish to create the application registration. Navigate to the applications tab and select the add command in the bottom pane. Select the ‘add an application my company is developing’ option.

ARM Auth - App Registration 1

1.2.1 Name and Type

Provide the name of the app (users will see this name on the consent screen). For type, leave the default selection (Web Application and/or Web API).

ARM Auth - App Registration 2

1.2.2 Sign-On URL and AppIDURI

In the next screen, for sign-on URL provide the reply URL of the application (this is where Azure AD will return the user/code+token after authentication). For AppIDURI – use the following string: http://<domain_name_of_you_directory>/<name_of_the_app>. So if your application name is cloudsense and the domain name of your directory is fabrikam.onmicrosoft.com, use ‘http://fabrikam.onmicrosoft.com/cloudsense’. For my sample application, I chose ‘http://www.vipswapper.com/cloudsense’.

ARM Auth - App Registration 3

1.2.3 Application Credential

Once the application registration is created, select the application and navigate to the configure tab of the application. Here, create a key credential (password). Your application will authenticate to Azure AD using this password.

ARM Auth - App Registration 4

1.2.4 Permissions to Other Applications

Your application will access Azure Resource Manager on behalf of the user to query subscriptions and configure RBAC access when user will connect/disconnect subscriptions with your application. To enable this you must configure the required delegated permissions in the ‘permissions to other applications’ section of your application registration. Leave the default ‘Enable single sign-on and read user’s profile’ delegated permission selection for ‘Windows Azure Active Directory’ in place. Add the ‘Access Azure Service Management’ delegated permission for ‘Windows Azure Service Management API’.

ARM Auth - App Registration 5

1.2.5 Multi-Tenant Setting

Finally, you must configure your app to be a multi-tenant application so that users from other Azure ADs can consent to it and sign-in to it.

ARM Auth - App Registration 6

1.2.6 Optional Configuration – Certificate Credential

Azure AD also supports certificate credentials for applications: you create a self-signed cert, keep the private key, and add the public key to your Azure AD application registration. For authentication, your application sends a small payload to Azure AD signed using your private key, and Azure AD validates the signature using the public key that you registered.

1.2.6.1 Create a Self-Signed Certificate

I used this PowerShell script to create a self-signed certificate and then exported its public key and thumbprint in base64.

[code lang=”powershell”]
. C:UsersdugillDocumentsWindowsPowerShellNew-SelfSignedCertificateEx.ps1

New-SelfSignedCertificateEx -Subject &amp;quot;cn=cloudsense,dc=vipswapper,dc=com&amp;quot; -NotBefore ([DateTime]::Now) -NotAfter ([DateTime]::Now.AddYears(100)) -FriendlyName &amp;quot;CloudSense App Cert Cred&amp;quot; -Path &amp;quot;C:tmpCloudSenseCred.pfx&amp;quot; -Password (ConvertTo-SecureString -AsPlainText p@ssw0rd -Force) –Exportable

$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate -ArgumentList &amp;quot;C:tmpCloudSenseCred.pfx&amp;quot;, &amp;lt;a href=&amp;quot;mailto:p@ssw0rd&amp;quot;&amp;gt;p@ssw0rd&amp;lt;/a&amp;gt;

[Convert]::ToBase64String($cer.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert))

[Convert]::ToBase64String($cer.GetCertHash())

[System.Guid]::NewGuid().ToString()
[/code]

ARM Auth - App Registration 8

1.2.6.2 Add Certificate Credential to Application Registration

Certificate Credentials for Azure AD applications can be managed using the application manifest json file. First, download the application manifest using the manage manifest command in the bottom pane.

ARM Auth - App Registration 9

Then, modify the json file to add a keyCredential object with the following properties:

Property

Value

type AsymmetricX509Cert
usage Verify
keyId Create a new guid
customKeyIdentifier base64 encoded thumbprint of the certificate
value base64 encoded public key of the certificate

For instance:

[code]
  {
    &amp;quot;customKeyIdentifier&amp;quot;: &amp;quot;nHmZ+nuUMcQzwD13L/UoWWh64B8=&amp;quot;,
    &amp;quot;keyId&amp;quot;: &amp;quot;ec1618e1-d004-41c3-9638-68cb36efc42e&amp;quot;,
    &amp;quot;type&amp;quot;: &amp;quot;AsymmetricX509Cert&amp;quot;,
    &amp;quot;usage&amp;quot;: &amp;quot;Verify&amp;quot;,
    &amp;quot;value&amp;quot;: &amp;quot;MIIDSTCCAjGgAwIB*****+pFFM=&amp;quot;
  }
[/code]

ARM Auth - App Registration 10

And upload the modified manifest file using ‘manage manifest’ command, to set the Certificate Credential for your application.

ARM Auth - App Registration 11

Note: if your receive concurrency error on uploading the modified manifest, check to see if the keyCredential has been set nevertheless (by downloading the manifest again). If the keyCredential has been set – ignore the error.

Also note: multiple keyCredentials can be associated with an application.

1.2.7 Optional Configuration – Logo and Additional Reply URLs

Optionally, you may add additional Reply URLs and a logo image for the application. In a future release, Azure AD will display the logo image of the application in the consent screen.

ARM Auth - App Registration 7

2. Develop your Application

We now have everything we need to get started with coding the application. For each step of the end-to-end flow that I have shown above, I shall provide the REST API reference and C# sample code. The ASP.net MVC application sample is here: https://github.com/dushyantgill/VipSwapper/tree/master/CloudSense. You can try it out here:http://www.vipswapper.com/cloudsense.

2.1 Authenticate User and Get (User + App) Access Token for ARM

We start at the point where the user gestures to connect their Azure subscription with your application. A common user experience is to show the user a list of cloud providers that the application supports, and the user selects ‘Microsoft Azure’. Now, your application must redirect the user to Azure AD with an OAuth 2.0 Authorize Request – to authenticate and get back an auth code, using which your application can get access token for ARM.

However, before you do that you must ask the user two things:

  1. Directory Domain Name: the domain name of the Azure Active Directory to which their Azure Subscription is associated. The OAuth 2.0 Authorization request must be sent to this Azure AD. The user can find out the domain name of their Azure AD by navigating to the Azure Management Portal and selecting the Settings node. You may choose to provide visual instructions to the user like: http://vipswapper.com/cloudsense/Images/directory.png
  2. Microsoft Account vs. Work Account: determine whether the user manages their Azure Subscription using a Microsoft Account (aka Live Id) or a Work Account (aka Organizational Account). If Microsoft Account, your application will redirect the user to the Azure Active Directory login page with a QS parameter (&domain_hint=live.com) that will instruct Azure AD to take the user directly to the Microsoft Account sign-in page. Note that the authorization code and tokens that you shall receive for either will be processed in the same way.

See the home page of the sample app for an example of how to receive this input from the user.

2.1.1 Auth Request (OAuth 2.0)

Issue an Open ID Connect/OAuth2.0 Authorize Request to the Azure AD Authorize endpoint (http://login.microsoftonline.com/{directory_domain_name}/OAuth2/Authorize) with the following QS parameters

2.1.1.1 OAuth2.0 Authorize Request QS Parameters

QS Parameter

Value

client_id Client ID of your application
response_mode ‘form_post’ or ‘query’
response_type ‘code’
redirect_uri URL encoded Reply URL of your application. For instance:
http%3a%2f%2fwww.vipswapper.com%2fcloudsense%2fAccount%2fSignIn
resource URL encoded identifier of Azure Service Management APIs:
‘https%3a%2f%2fmanagement.core.windows.net%2f’
domain_hint ‘live.com’
Note: only use the domain_hint parameter if the user manages their Azure Subscription using a Microsoft Account.
state Optionally, specify any state data that you wish Azure AD to return back with the response.
2.1.1.2 Example OAuth2.0 Authorize Request

[code]
https://login.windows.net/dushyantgill.com/OAuth2/Authorize?client_id=a0448380-c346-4f9f-b897-c18733de9394&amp;response_mode=query&amp;response_type=code&amp;redirect_uri=http%3a%2f%2fwww.vipswapper.com%2fcloudsense%2fAccount%2fSignIn&amp;resource=https%3a%2f%2fgraph.windows.net%2f&amp;domain_hint=live.com
[/code]

2.1.1.3 Example OAuth2.0 Authorize Response

Azure AD authenticates the user, (if required, asks the user to consent) and returns back the authorization code to the Reply URL of your application. Depending on the requested response_mode, Azure AD either sends back the data in query string or as post data.

[code]
code=AAABAAAAiL****FDMZBUwZ8eCAA&amp;amp;session_state=2d16bbce-d5d1-443f-acdf-75f6b0ce8850
[/code]

2.1.2 Auth Request (Open ID Connect)

If you not only with to access Azure Resource Manager on behalf of the user, but also allow the user to sign-in to your application using their Azure AD account, issue an Open ID Connect Authorize Request. With Open ID Connect, your application will also receive an id_token from Azure AD that your app can use to sign-in the user.

2.1.2.1 OAuth2.0 Authorize Request QS Parameters

QS Parameter

Value

client_id Client ID of your application
response_mode ‘form_post’ or ‘query’
response_type ‘code+id_token’
redirect_uri URL encoded Reply URL of your application. For instance:
http%3a%2f%2fwww.vipswapper.com%2fcloudsense%2fAccount%2fSignIn
resource URL encoded identifier of Azure Service Management APIs:
‘https%3a%2f%2fmanagement.core.windows.net%2f’
scope ‘openid+profile’
nonce Piece of data to tie the authorize request to the returned id_token to ensure that the authorize response is solicited and isn’t replayed.
domain_hint ‘live.com’
Note: only use the domain_hint parameter if the user manages their Azure Subscription using a Microsoft Account.
state Optionally, specify any state data that you wish Azure AD to return back with the response.
2.1.2.2 Example Open ID Connect Request

[code]
https://login.windows.net/dushyantgill.com/OAuth2/Authorize?client_id=a0448380-c346-4f9f-b897-c18733de9394&amp;response_mode=form_post&amp;response_type=code+id_token&amp;redirect_uri=http%3a%2f%2fwww.vipswapper.com%2fcloudsense%2fAccount%2fSignIn&amp;resource=https%3a%2f%2fgraph.windows.net%2f&amp;scope=openid+profile&amp;nonce=63567Dc4MDAw&amp;domain_hint=live.com&amp;state=M_12tMyKaM8
[/code]

2.1.2.3 Example Open ID Connect Response

Azure AD authenticates the user, (if required, asks the user to consent) and returns back the authorization code to the Reply URL of your application. Depending on the requested response_mode, Azure AD either sends back the data in query string or as post data.

[code]
code=AAABAAAAiL*****I4rDWd7zXsH6WUjlkIEQxIAA&amp;amp;id_token=eyJ0eXAiOiJKV1Q*****T3GrzzSFxg&amp;amp;state=M_12tMyKaM8&amp;amp;session_state=2d16bbce-d5d1-443f-acdf-75f6b0ce8850
[/code]

2.1.2.4 Validate id_token

Before your application signs-in the user it must validate the id_token. Token validation is an involved topic, and I recommend that you use a standard JSON Web Token handler library for your development platform. (the .net Azure AD JWT Handler source code is published here). That said, security of your application is your responsibility, so make sure that the library that you use to handle the id_token properly validates the following aspects of the token:

  • Timing of the token: check the nbf and exp claims to ensure that the token isn’t too fresh or too stale. It is customary to keep some slack (5 minutes) to accommodate time skews.
  • Issuer: check the iss claim to ensure the issuer of the token is Azure Active Directory: https://sts.windows.net/{tenant_id_of_the_directory}
  • Audience: check the aud claim to ensure that the token has been minted for your application. The value must be the Client ID of your application.
  • Nonce: check the nonce claim to check against the nonce data that you sent in the authorization request, to ensure that the response has been solicited by your application and that the token isn’t being replayed.
  • Signature: your app must verify that the token has been signed by Azure Active Directory. Get the signing key of Azure AD from here:. Azure AD signing keys roll frequently, so your app must either poll for refreshed keys daily or fault-in the refreshed keys if signature validation fails. Get Azure AD signing keys from here.

Once the id_token has been validated, use the oid claim value as the immutable and non-reusable identifier of the user. Use either unique_name claim or the upn/email claim as the human readable display name of the user. You may also use the optional given_name/family_name claims for display purpose.

Here’s a sample Azure AD id_token for a Work Account and here’s one for a Microsoft Account.

2.1.2 Token Request (OAuth2.0 Code Grant Flow)

Now that your application has received the auth code from Azure AD it is time to get access token for Azure Resource Manager: post an OAuth2.0 Code Grant Token Request to the Azure AD Token endpoint (http://login.microsoftonline.com/{directory_domain_name}/OAuth2/Token)

2.1.2.1 Code Grant Token Request Data – Password Cred

Element

Value

grant_type ‘authorization_code’
code URL encoded authorization code (received as part of authorization result)
redirect_uri URL encoded Reply URL of your application. For instance:
http%3a%2f%2fwww.vipswapper.com%2fcloudsense%2fAccount%2fSignIn
client_id Client ID of your application
client_secret URL encoded Password Credential of your application
2.1.2.2 Example Code Grant Token Request – Password Cred

[code]
POST https://login.windows.net/7fe877e6-a150-4992-bbfe-f517e304dfa0/oauth2/token HTTP/1.1

Content-Type: application/x-www-form-urlencoded
Content-Length: 1012

grant_type=authorization_code&amp;amp;code=AAABAAAAiL9Kn2Z*****L1nVMH3Z5ESiAA&amp;amp;redirect_uri=http%3A%2F%2Flocalhost%3A62080%2FAccount%2FSignIn&amp;amp;client_id=a0448380-c346-4f9f-b897-c18733de9394&amp;amp;client_secret=olna84E8*****goScOg%3D
[/code]

2.1.2.3 Code Grant Token Request Data – Cert Cred
Element

Value

grant_type ‘authorization_code’
code URL encoded authorization code (received as part of authorization result)
redirect_uri URL encoded Reply URL of your application. For instance:
http%3a%2f%2fwww.vipswapper.com%2fcloudsense%2fAccount%2fSignIn
client_id Client ID of your application
client_assertion_type ‘urn:ietf:params:oauth:client-assertion-type:jwt-bearer’
client_assertion Client Assertion JWT token signed using the Certificate Credential Private Key
2.1.2.4 Create Client Assertion JWT Token

Create a JWT token with the following claims and sign (RSA SHA256) using the private key of your application’s Certificate Credential. Active Directory Auth Library (.net) uses this code to sign Client Assertion JWT tokens – you may use it as reference.

Claim

Value

aud https://login.windows.net/{directory_domain_name}/oauth2/token
iss Client ID of your application.
sub Client ID of your application.
jti A unique identifier for the token.
nbf Not before time of the token.
exp Expiry time of the token.

See this section of the Open ID Connect spec for details on Client Authentication. Here’s a sample client assertion JWT token.

2.1.2.5 Example Code Grant Token Request – Cert Cred

[code]
POST https://login.windows.net/7fe877e6-a150-4992-bbfe-f517e304dfa0/oauth2/token HTTP/1.1

Content-Type: application/x-www-form-urlencoded
Content-Length: 1012

grant_type=authorization_code&amp;amp;code=AAABAAAAiL9Kn2Z*****L1nVMH3Z5ESiAA&amp;amp;redirect_uri=http%3A%2F%2Flocalhost%3A62080%2FAccount%2FSignIn&amp;amp;client_id=a0448380-c346-4f9f-b897-c18733de9394&amp;amp;client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&amp;amp;client_assertion=eyJhbG*****Y9cYo8nEjMyA
[/code]

2.1.2.6 Example Code Grant Token Response

[code]
HTTP/1.1 200 OK

{&amp;quot;token_type&amp;quot;:&amp;quot;Bearer&amp;quot;,&amp;quot;expires_in&amp;quot;:&amp;quot;3599&amp;quot;,&amp;quot;expires_on&amp;quot;:&amp;quot;1432039858&amp;quot;,&amp;quot;not_before&amp;quot;:&amp;quot;1432035958&amp;quot;,&amp;quot;resource&amp;quot;:&amp;quot;https://management.core.windows.net/&amp;quot;,&amp;quot;access_token&amp;quot;:&amp;quot;eyJ0eXAiOiJKV1Q****M7Cw6JWtfY2lGc5A&amp;quot;,&amp;quot;refresh_token&amp;quot;:&amp;quot;AAABAAAAiL9Kn2Z****55j-sjnyYgAA&amp;quot;,&amp;quot;scope&amp;quot;:&amp;quot;user_impersonation&amp;quot;,&amp;quot;id_token&amp;quot;:&amp;quot;eyJ0eXAiOiJKV*****-drP1J3P-HnHi9Rr46kGZnukEBH4dsg&amp;quot;}
[/code]

2.1.2.7 Handle Code Grant Token Response

Successful token response will contain the (User + App) access token for Azure Resource Manager. Your application will use this access token to access ARM on behalf of the user. The lifetime of access tokens issued by Azure AD is one hour. It is unlikely that your web application will need to renew the (User + App) access token – however, if it does, you may use the refresh token that your application receives in the token response: post an OAuth2.0 Token Request to the Azure AD Token endpoint (http://login.microsoftonline.com/{directory_domain_name}/OAuth2/Token)

2.1.2.8 Refresh Token Grant Token Request Data

Element

Value

grant_type ‘refresh_token’
refresh_token URL encoded refresh token (received as part of token response)
client_id Client ID of your application
client_secret or client_assertion_type + client_assertion If your application uses password credential then use client_secret (see section 2.1.2.1)If your application uses certificate credential then use client_assertion (see section 2.1.2.3)
2.1.2.9 Example Refresh Token Grant Token Request

[code]
POST https://login.windows.net/7fe877e6-a150-4992-bbfe-f517e304dfa0/oauth2/token HTTP/1.1

Content-Type: application/x-www-form-urlencoded
Content-Length: 1012

grant_type=refresh_token&amp;amp;refresh_token=AAABAAAAiL9Kn2Z****55j-sjnyYgAA&amp;amp;client_id=a0448380-c346-4f9f-b897-c18733de9394&amp;amp;client_secret=olna84E8*****goScOg%3D
[/code]

Note that although refresh tokens can be used to get new access tokens for Azure Resource Manager, they are not suitable for “offline access” by your application. 1) refresh tokens lifetime is limited 2) refresh tokens are bound to the user. So if the user leaves the organization, the application using the refresh token loses access. This isn’t suitable for applications that are used by teams to manage their Azure resources.

2.2 List Subscriptions that User Can Connect With You App

Your application now has a token using which it can access Azure Resource Manager on behalf of the user.

The next step of the experience is to allow the user to connect their Azure subscription with your application such that your app can manage those subscriptions even when the user isn’t present (long-term offline access). For this, you should show the user the list of their Azure subscriptions on which they can manage access, and allow them to assign an RBAC role directly to your application’s identity, on the subscriptions that they wish to connect.

ARM Auth - Sample App Ux 4

2.2.1 List Subscriptions in which the User has any access

We shall first call the ARM subscriptions API to list all subscriptions in which the user has any kind of access. Then, we will identify the ones for which the user can manage access.

The GetUserSubscription method of the ASP.net MVC sample app implements this call.

2.2.1.1 Example List Subscriptions Request

[code]
GET https://management.azure.com/subscriptions?api-version=2014-04-01-preview HTTP/1.1

Authorization: Bearer eyJ0eXAiOiJKV1QiLC***lwO1mM7Cw6JWtfY2lGc5A
[/code]

2.2.1.2 Example List Subscriptions Response

[code]
HTTP/1.1 200 OK

{&amp;quot;value&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;/subscriptions/34370e90-ac4a-4bf9-821f-85eeedeae1a2&amp;quot;,&amp;quot;subscriptionId&amp;quot;:&amp;quot;34370e90-ac4a-4bf9-821f-85eeedeae1a2&amp;quot;,&amp;quot;displayName&amp;quot;:&amp;quot;Sandbox&amp;quot;,&amp;quot;state&amp;quot;:&amp;quot;Enabled&amp;quot;,&amp;quot;subscriptionPolicies&amp;quot;:{&amp;quot;locationPlacementId&amp;quot;:&amp;quot;Public_2014-09-01&amp;quot;,&amp;quot;quotaId&amp;quot;:&amp;quot;PayAsYouGo_2014-09-01&amp;quot;}},{&amp;quot;id&amp;quot;:&amp;quot;/subscriptions/c276fc76-9cd4-44c9-99a7-4fd71546436e&amp;quot;,&amp;quot;subscriptionId&amp;quot;:&amp;quot;c276fc76-9cd4-44c9-99a7-4fd71546436e&amp;quot;,&amp;quot;displayName&amp;quot;:&amp;quot;Production&amp;quot;,&amp;quot;state&amp;quot;:&amp;quot;Enabled&amp;quot;,&amp;quot;subscriptionPolicies&amp;quot;:{&amp;quot;locationPlacementId&amp;quot;:&amp;quot;Public_2014-09-01&amp;quot;,&amp;quot;quotaId&amp;quot;:&amp;quot;PayAsYouGo_2014-09-01&amp;quot;}}]}
[/code]

2.2.2 Get User’s Permissions on Subscription

The connect/disconnect action should only be displayed for subscriptions for which the user can manage access. For each subscription, we shall call the ARM Permissions API to determine whether or not the user has Access Management rights for the subscription.

The UserCanManagerAccessForSubscription method of the ASP.net MVC sample app implements this call.

2.2.2.1 Example Get User’s Permissions on Subscription Request

[code]
GET https://management.azure.com/subscriptions/83cfe939-2402-4581-b761-4f59b0a041e4/providers/microsoft.authorization/permissions?api-version=2014-07-01-preview HTTP/1.1

Authorization: Bearer eyJ0eXAiOiJKV1QiLC***lwO1mM7Cw6JWtfY2lGc5A
[/code]

83cfe939-2402-4581-b761-4f59b0a041e4 is the id of the subscription.

2.2.2.2 Example Get User’s Permissions on Subscription Response

[code]
HTTP/1.1 200 OK

{&amp;quot;value&amp;quot;:[{&amp;quot;actions&amp;quot;:[&amp;quot;*&amp;quot;],&amp;quot;notActions&amp;quot;:[&amp;quot;Microsoft.Authorization/*/Write&amp;quot;,&amp;quot;Microsoft.Authorization/*/Delete&amp;quot;]},{&amp;quot;actions&amp;quot;:[&amp;quot;*/read&amp;quot;],&amp;quot;notActions&amp;quot;:[]}]}
[/code]

The Permissions API returns multiple permissions. Each permission consists of allowed actions (actions) and not allowed actions (notactions). If an action is present in the allowed actions list of any permission and not present in the notactions list of that permission, then the user is allowed to perform that action.

‘microsoft.authorization/roleassignments/write’ is the action that that grants access management rights. Your application must parse the permissions result to look for a regex match on this action string in the actions and notactions of each permission.

2.2.3 Optional: List Directories in which User account is present

A user’s account can be present in multiple Azure Active Directories. It is possible that the user didn’t specify the correct directory name initially – in that case the desired subscription wouldn’t be displayed in the list.

ARM Tenants API lists the identifiers of all directories in which the user’s account is present. You may call the API to determine whether the user’s account is in more than one directory and optionally show them a message like “Didn’t find the subscription you were looking for? It could be in the other Azure Active Directory of which you are a member. Click here to switch directory.”

The GetUserOrganizations method of the ASP.net MVC sample app implements this call.

2.2.1.1 Example List Directories Request

[code]
GET https://management.azure.com/tenants?api-version=2014-04-01-preview HTTP/1.1

Authorization: Bearer eyJ0eXAiOiJKV1Qi****8DJf1UO4a-ZZ_TJmWFlwO1mM7Cw6JWtfY2lGc5A
[/code]

2.2.1.2 Example List Directories Response

[code]
HTTP/1.1 200 OK

{&amp;quot;value&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;/tenants/7fe877e6-a150-4992-bbfe-f517e304dfa0&amp;quot;,&amp;quot;tenantId&amp;quot;:&amp;quot;7fe877e6-a150-4992-bbfe-f517e304dfa0&amp;quot;},{&amp;quot;id&amp;quot;:&amp;quot;/tenants/62e173e9-301e-423e-bcd4-29121ec1aa24&amp;quot;,&amp;quot;tenantId&amp;quot;:&amp;quot;62e173e9-301e-423e-bcd4-29121ec1aa24&amp;quot;}]}
[/code]

2.3 “Connect” Subscription with Application

You now have a list Azure subscriptions that the user can connect to your application. The next step is to give user a command to create the connection. A few things happen when the user clicks connect

  • Step 1) Assign the appropriate RBAC role to your application’s identity on the subscription.
  • Step 2) Validate the access assignment by querying for the Application’s permission on the subscription or by accessing ARM using app-only token.
  • Step 3) Record the connection in your applications “connected subscriptions” data structure – persisting the id of the subscription. And

Let’s look closer at the first step: to assign the appropriate RBAC role to the application’s identity, you must determine

  • Step 1a) The object id of your application’s identity in the user’s Azure Active Directory
  • Step 1b) The identifier of the RBAC role that your application requires on the subscription, to do its job

Let’s drill into the first part: the first time your application authenticates a user from an Azure AD, a Service Principal object for your application gets created in that Azure AD. Azure allows RBAC roles to be assigned to Service Principals, to grant direct access to corresponding Applications on Azure resources. This is exactly what we wish to do – so we begin by querying the Azure AD Graph API to determine the identifier of the Service Principal of your Application in the signed-in user’s Azure AD.

We only have an access token for Azure Resource Manager – we need a new access token to call the Azure AD Graph API. Every application in Azure AD has the permission to query its own Service Principal object, so we don’t need a User + App access token for this, an App-Only access token will suffice.

2.3.1 Get App-Only Access Token for Azure AD Graph API

Issue a Client Credential Grant OAuth2.0 flow token request to Azure AD token endpoint (http://login.microsoftonline.com/{directory_domain_name}/OAuth2/Token), to authenticate your app and get a token to Azure AD Graph API.

Lines 73-77 of GetObjectIdOfServicePrincipalInOrganization method of the ASP.net MVC sample application gets an app-only access token for Graph API using the Active Directory Authentication Library for .net.

2.3.1.1 Client Credential Grant Token Request Data

Element

Value

grant_type ‘client_credentials’
client_id Client ID of your application
resource URL encoded identifier of the resource for which the access token is being requested. In this case, the identifier of the Azure AD Graph API:‘https%3A%2F%2Fgraph.windows.net%2F’
client_secret or client_assertion_type + client_assertion If your application uses password credential then use client_secret (see section 2.1.2.1)If your application uses certificate credential then use client_assertion (see section 2.1.2.3)
2.3.1.2 Example Client Credential Grant Token Request

[code]
POST https://login.windows.net/62e173e9-301e-423e-bcd4-29121ec1aa24/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 187&amp;lt;/pre&amp;gt;
&amp;lt;pre&amp;gt;grant_type=client_credentials&amp;amp;client_id=a0448380-c346-4f9f-b897-c18733de9394&amp;amp;resource=https%3A%2F%2Fgraph.windows.net%2F &amp;amp;client_secret=olna8C*****Og%3D
[/code]

2.3.1.3 Example Client Credential Grant Token Response

[code]
HTTP/1.1 200 OK

{&amp;quot;token_type&amp;quot;:&amp;quot;Bearer&amp;quot;,&amp;quot;expires_in&amp;quot;:&amp;quot;3599&amp;quot;,&amp;quot;expires_on&amp;quot;:&amp;quot;1432039862&amp;quot;,&amp;quot;not_before&amp;quot;:&amp;quot;1432035962&amp;quot;,&amp;quot;resource&amp;quot;:&amp;quot;https://graph.windows.net/&amp;quot;,&amp;quot;access_token&amp;quot;:&amp;quot;eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSIsImtpZCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSJ9.eyJhdWQiOiJodHRwczovL2dyYXBoLndpbmRv****G5gUTV-kKorR-pg&amp;quot;}
[/code]

2.3.2 Get ObjectId of Application’ Service Principal in User’ Azure AD

Now, we use the App-Only access token to query the Azure AD Graph Service Principals API to determine the Object Id of the Application’s Service Principal in the directory.

The GetObjectIdOfServicePrincipalInOrganiation method of the ASP.net MVC sample application implements this call.

2.3.2.1 Example Get Application’s Service Principal Request

[code]
GET https://graph.windows.net/62e173e9-301e-423e-bcd4-29121ec1aa24/servicePrincipals?api-version=1.5&amp;amp;$filter=appId%20eq%20’a0448380-c346-4f9f-b897-c18733de9394′ HTTP/1.1

Authorization: Bearer eyJ0eXAiOiJK*****-kKorR-pg
[/code]

a0448380-c346-4f9f-b897-c18733de9394 is the client id of the application.

2.3.2.2 Example Get Application’s Service Principal Response

[code]
HTTP/1.1 200 OK

{&amp;quot;odata.metadata&amp;quot;:&amp;quot;https://graph.windows.net/62e173e9-301e-423e-bcd4-29121ec1aa24/$metadata#directoryObjects/Microsoft.DirectoryServices.ServicePrincipal&amp;quot;,&amp;quot;value&amp;quot;:[{&amp;quot;odata.type&amp;quot;:&amp;quot;Microsoft.DirectoryServices.ServicePrincipal&amp;quot;,&amp;quot;objectType&amp;quot;:&amp;quot;ServicePrincipal&amp;quot;,&amp;quot;objectId&amp;quot;:&amp;quot;9b5018d4-6951-42ed-8a92-f11ec283ccec&amp;quot;,&amp;quot;deletionTimestamp&amp;quot;:null,&amp;quot;accountEnabled&amp;quot;:true,&amp;quot;appDisplayName&amp;quot;:&amp;quot;CloudSense&amp;quot;,&amp;quot;appId&amp;quot;:&amp;quot;a0448380-c346-4f9f-b897-c18733de9394&amp;quot;,&amp;quot;appOwnerTenantId&amp;quot;:&amp;quot;62e173e9-301e-423e-bcd4-29121ec1aa24&amp;quot;,&amp;quot;appRoleAssignmentRequired&amp;quot;:false,&amp;quot;appRoles&amp;quot;:[],&amp;quot;displayName&amp;quot;:&amp;quot;CloudSense&amp;quot;,&amp;quot;errorUrl&amp;quot;:null,&amp;quot;homepage&amp;quot;:&amp;quot;http://www.vipswapper.com/cloudsense&amp;quot;,&amp;quot;keyCredentials&amp;quot;:[],&amp;quot;logoutUrl&amp;quot;:null,&amp;quot;oauth2Permissions&amp;quot;:[{&amp;quot;adminConsentDescription&amp;quot;:&amp;quot;Allow the application to access CloudSense on behalf of the signed-in user.&amp;quot;,&amp;quot;adminConsentDisplayName&amp;quot;:&amp;quot;Access CloudSense&amp;quot;,&amp;quot;id&amp;quot;:&amp;quot;b7b7338e-683a-4796-b95e-60c10380de1c&amp;quot;,&amp;quot;isEnabled&amp;quot;:true,&amp;quot;type&amp;quot;:&amp;quot;User&amp;quot;,&amp;quot;userConsentDescription&amp;quot;:&amp;quot;Allow the application to access CloudSense on your behalf.&amp;quot;,&amp;quot;userConsentDisplayName&amp;quot;:&amp;quot;Access CloudSense&amp;quot;,&amp;quot;value&amp;quot;:&amp;quot;user_impersonation&amp;quot;}],&amp;quot;passwordCredentials&amp;quot;:[],&amp;quot;preferredTokenSigningKeyThumbprint&amp;quot;:null,&amp;quot;publisherName&amp;quot;:&amp;quot;vipswapper&amp;quot;,&amp;quot;replyUrls&amp;quot;:[&amp;quot;http://www.vipswapper.com/cloudsense&amp;quot;,&amp;quot;http://www.vipswapper.com&amp;quot;,&amp;quot;http://vipswapper.com&amp;quot;,&amp;quot;http://vipswapper.azurewebsites.net&amp;quot;,&amp;quot;http://localhost:62080&amp;quot;],&amp;quot;samlMetadataUrl&amp;quot;:null,&amp;quot;servicePrincipalNames&amp;quot;:[&amp;quot;http://www.vipswapper.com/cloudsense&amp;quot;,&amp;quot;a0448380-c346-4f9f-b897-c18733de9394&amp;quot;],&amp;quot;tags&amp;quot;:[&amp;quot;WindowsAzureActiveDirectoryIntegratedApp&amp;quot;]}]}
[/code]

2.3.3 Get Azure RBAC Role Identifier

Now, the appropriate RBAC role must be assigned to your applications Service Principal on the selected subscription. For this you must determine the identifier of the Azure RBAC role.

The right RBAC role for your application

  • If your application only will only monitor Azure on an on-going basis, without making any changes, it is likely that it requires only reader permissions on the subscription. You must assign the ‘Reader’ role
  • On the other hand if your application manages Azure on an on-going basis, creating/modifying/deleting entities, it will require contributor permissions.
    • Assign the appropriate resource type specific contributor roles (e.g. Virtual Machine Contributor, Virtual Network Contributor, Storage Account Contributor etc.)
    • If your application indeed needs broad contributor permissions (manage any resource), then assign the ‘Contributor’ role.

Note that the role assignment to your application will be visible to users of the subscription in Azure management portal and command line tools – so, follow the principal of least privilege.

ARM Auth - Sample App Ux 6

Call the ARM role definition API to list all Azure RBAC roles and search then iterate over the result to find the desired role definition by name.

The GetRoleId method of the ASP.net MVC sample app implements this call.

2.3.3.1 Example Get Azure RBAC Role Identifier Request

[code]
GET https://management.azure.com/subscriptions/09cbd307-aa71-4aca-b346-5f253e6e3ebb/providers/Microsoft.Authorization/roleDefinitions?api-version=2014-07-01-preview HTTP/1.1

Authorization: Bearer eyJ0eXAiOiJKV*****fY2lGc5
[/code]

09cbd307-aa71-4aca-b346-5f253e6e3ebb is the id of the subscription.

2.3.3.2 Example Get Azure RBAC Role Identifier Response

[code]
HTTP/1.1 200 OK

{&amp;quot;value&amp;quot;:[{&amp;quot;properties&amp;quot;:{&amp;quot;roleName&amp;quot;:&amp;quot;API Management Service Contributor&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;BuiltInRole&amp;quot;,&amp;quot;description&amp;quot;:&amp;quot;Lets you manage API Management services, but not access to them.&amp;quot;,&amp;quot;scope&amp;quot;:&amp;quot;/&amp;quot;,&amp;quot;permissions&amp;quot;:[{&amp;quot;actions&amp;quot;:[&amp;quot;Microsoft.ApiManagement/Services/*&amp;quot;,&amp;quot;Microsoft.Authorization/*/read&amp;quot;,&amp;quot;Microsoft.Resources/subscriptions/resources/read&amp;quot;,&amp;quot;Microsoft.Resources/subscriptions/resourceGroups/read&amp;quot;,&amp;quot;Microsoft.Resources/subscriptions/resourceGroups/resources/read&amp;quot;,&amp;quot;Microsoft.Resources/subscriptions/resourceGroups/deployments/*&amp;quot;,&amp;quot;Microsoft.Insights/alertRules/*&amp;quot;,&amp;quot;Microsoft.Support/*&amp;quot;],&amp;quot;notActions&amp;quot;:[]}]},&amp;quot;id&amp;quot;:&amp;quot;/subscriptions/09cbd307-aa71-4aca-b346-5f253e6e3ebb/providers/Microsoft.Authorization/roleDefinitions/312a565d-c81f-4fd8-895a-4e21e48d571c&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;Microsoft.Authorization/roleDefinitions&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;312a565d-c81f-4fd8-895a-4e21e48d571c&amp;quot;},{&amp;quot;properties&amp;quot;:{&amp;quot;roleName&amp;quot;:&amp;quot;Application Insights Component Contributor&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;BuiltInRole&amp;quot;,&amp;quot;description&amp;quot;:&amp;quot;Lets you manage Application Insights components, but not access to them.&amp;quot;,&amp;quot;scope&amp;quot;:&amp;quot;/&amp;quot;,&amp;quot;permissions&amp;quot;:[{&amp;quot;actions&amp;quot;:[&amp;quot;Microsoft.Insights/components/*&amp;quot;,&amp;quot;Microsoft.Insights/webtests/*&amp;quot;,&amp;quot;Microsoft.Authorization/*/read&amp;quot;,&amp;quot;Microsoft.Resources/subscriptions/resources/read&amp;quot;,&amp;quot;Microsoft.Resources/subscriptions/resourceGroups/read&amp;quot;,&amp;quot;Microsoft.Resources/subscriptions/resourceGroups/resources/read&amp;quot;,&amp;quot;Microsoft.Resources/subscriptions/resourceGroups/deployments/*&amp;quot;,&amp;quot;Microsoft.Insights/alertRules/*&amp;quot;,&amp;quot;Microsoft.Support/*&amp;quot;],&amp;quot;notActions&amp;quot;:[]}]},&amp;quot;id&amp;quot;:&amp;quot;/subscriptions/09cbd307-aa71-4aca-b346-5f253e6e3ebb/providers/Microsoft.Authorization/roleDefinitions/ae349356-3a1b-4a5e-921d-050484c6347e&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;Microsoft.Authorization/roleDefinitions&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;ae349356-3a1b-4a5e-921d-050484c6347e&amp;quot;}]}
[/code]

Note that you do not need to call this API on an ongoing basis. Once you’ve determined the well-known GUID of the role definition, you can construct the role definition id as:

“/subscriptions/{subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{well-known-role-guid}”. Here’ the well-known guids of commonly used built-in roles:

  • Reader: acdd72a7-3385-48ef-bd42-f606fba81ae7
  • Contributor: b24988ac-6180-42a0-ab88-20f7382dd24c
  • Virtual Machine Contributor: d73bb868-a0df-4d4d-bd69-98a00b01fccb
  • Virtual Network Contributor: b34d265f-36f7-4a0d-a4d4-e158ca92e90f
  • Storage Account Contributor: 86e8f5dc-a6e9-4c67-9d15-de283e8eac25
  • Website Contributor: de139f84-1756-47ae-9be6-808fbbe84772
  • Web Plan Contributor: 2cc479cb-7b4d-49a8-b449-8c00fd0f0a4b
  • SQL Server Contributor: 6d8ee4ec-f05a-4a1d-8b00-a9b17e38b437
  • SQL DB Contributor: 9b7fa17d-e63e-47b0-bb0a-15c516ac86ec
2.3.4 Assign RBAC role to Application

We now have everything we need to assign the appropriate RBAC role to your applications service principal on the selected subscription, using the ARM create role assignment API.

The GrantRoleToServicePrincipalOnSubscription method of the ASP.net MVC sample app implements this call.

2.3.4.1 Example Assign RBAC role to Application Request

[code]
PUT https://management.azure.com/subscriptions/09cbd307-aa71-4aca-b346-5f253e6e3ebb/providers/microsoft.authorization/roleassignments/4f87261d-2816-465d-8311-70a27558df4c?api-version=2014-10-01-preview HTTP/1.1

Authorization: Bearer eyJ0eXAiOiJKV1QiL*****FlwO1mM7Cw6JWtfY2lGc5
Content-Type: application/jso
Content-Length: 230

{&amp;quot;properties&amp;quot;: {&amp;quot;roleDefinitionId&amp;quot;:&amp;quot;/subscriptions/09cbd307-aa71-4aca-b346-5f253e6e3ebb/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7&amp;quot;,&amp;quot;principalId&amp;quot;:&amp;quot;c3097b31-7309-4c59-b4e3-770f8406bad2&amp;quot;}}
[/code]

09cbd307-aa71-4aca-b346-5f253e6e3ebb is the id of the subscription.

c3097b31-7309-4c59-b4e3-770f8406bad2 is the object id of the service principal of the application.

acdd72a7-3385-48ef-bd42-f606fba81ae7 is the well-known guid of the Reader RBAC role.

4f87261d-2816-465d-8311-70a27558df4c is a new guid created for the new role assignment.

2.3.4.2 Example Assign RBAC role to Application Response

[code]
HTTP/1.1 201 Created

{&amp;quot;properties&amp;quot;:{&amp;quot;roleDefinitionId&amp;quot;:&amp;quot;/subscriptions/09cbd307-aa71-4aca-b346-5f253e6e3ebb/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7&amp;quot;,&amp;quot;principalId&amp;quot;:&amp;quot;c3097b31-7309-4c59-b4e3-770f8406bad2&amp;quot;,&amp;quot;scope&amp;quot;:&amp;quot;/subscriptions/09cbd307-aa71-4aca-b346-5f253e6e3ebb&amp;quot;},&amp;quot;id&amp;quot;:&amp;quot;/subscriptions/09cbd307-aa71-4aca-b346-5f253e6e3ebb/providers/Microsoft.Authorization/roleAssignments/4f87261d-2816-465d-8311-70a27558df4c&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;Microsoft.Authorization/roleAssignments&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;4f87261d-2816-465d-8311-70a27558df4c&amp;quot;}
[/code]

2.3.5 Get App-Only Access Token for Azure Resource Manager

The next step is to validate that app has desired access on the subscription. For this, you should perform a test task on the subscription using an App-Only token for Azure Resource Manager. The test task should validate that your application does indeed have the desired access on the subscription, to perform offline monitoring/management.

To get an app-only access token for Azure Resource Manager, follow instructions from section 2.3.1, with a different value for the resource parameter: ‘https%3A%2F%2Fmanagement.core.windows.net%2F’

Lines 210-214 of ServicePrincipalHasReadAccessToSubscription method of the ASP.net MVC sample application gets an app-only access token for Azure Resource Manager using the Active Directory Authentication Library for .net.

2.3.6 Get Application’s Permissions on Subscription

To check that your application has the desired access on an Azure subscription, you may also call the ARM Permissions API similar to how you determined whether or not the user has Access Management rights for the subscription in section 2.2.2. However, this time call the permissions API with the app-only access token that you received in the previous step.

The ServicePrincipalHasReadAccessToSubscription method of the ASP.net MVC sample app implements this call.

2.3 On-Going Management of “Connected” Subscriptions

Once an Azure subscription is connected with your application (i.e. the appropriate RBAC role is assigned to your applications service principal on the subscription) – your application can keep monitoring/managing it using app-only access tokens for Azure Resource Manager.

If a subscription owner removes your application’s role assignment using Azure Management Portal or command line tools, your application will no longer be able to access that subscription. In that case, you should notify the user that the connection with the subscription was severed from outside the application and give them an option to “repair” the connection. “Repair” would simply re-create the role assignment that was deleted offline.

ARM Auth - Sample App Ux 7

2.4 “Disconnect” Subscription from Application

Just as you enabled users to connect their subscriptions to your application, you must allow then to disconnect subscriptions too. From an access management point of view, disconnect means removing the role assignment that the applications service principal has on the subscription. Optionally, any state in the application for the subscription might be removed too. Akin to connect, only users with access management permission on the subscription will be able to disconnect the subscription.

The RevokeRoleFromServicePrincipalOnSubscription method of the ASP.net MVC sample app implements this call.
—–

There you go – users can now easily connect and manage their Azure subscriptions with your application.

I shall also leave you with a fiddler trace of the end to end flow of the sample application (including POST, PUT and DELETE calls).

Let me know if you hit a snag.

Enjoy!

7 thoughts on “Developer’s guide to auth with Azure Resource Manager API

  1. Pingback: Certificate-based auth with Azure Service Principals from Linux command line - Arsen Vladimirskiy - Site Home - MSDN Blogs

  2. Steve Brownell

    Thank you so much for this post. It’s clear and directly to the task at hand. It is also very useful to see the complete OAuth flow as a series of requests and responses, instead of handing that over to a library (like ADAL).

  3. Steve Brownell

    So, the delegate permissions changed today (or in the last couple days). The “Access Azure Service Management (preview)” is gone. In its place is a series of Read/Write directory permissions. What new choice is equivalent to the prior value? Does this change anything else?

    1. Steve Brownell

      A selected all possible options, but my request continues to return error AADST565005: “This request has failed because the client has not specified this resource in its requiredResourceAccess list.”

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>