Using OAuth 2.0 Authorization Code Grant for delegated access of Directory via AAD Graph
Updated: Feb 14, 2014 - the Permissions section below has bee revised to use who how to configure an App, to use OAuth 2.0 Authorization Code Grant, by using the Azure Management Portal's Application Configuration capabilities.
You might have seen the recent announcement of developer preview for support of OAuth Code Grant in Azure Active Directory. You can use this to provide delegated access when accessing resources. We can use the same mechanism to access AAD resources using delegated access via Graph API. We have an updated PHP sample that shows how to use this. The blog post provides details on what’s required in building such an application.
Using Authorization Code v/s Client Credentials
In our previous posts on this blog and our samples web site, we have shown various kinds of Applications you can build that consume information from AAD Graph. But the one thing that was common to all the applications was that they used Application credentials exclusively when talking to AAD Graph and did not use User identity. Since the user identity is not used in the Client Credentials flow, the application has to take the responsibility for making sure that the users are authenticated and are given the appropriate level of access when accessing resources in AAD. Users get different permissions in AAD depending on the role they belong to. For example, all Users get permissions to read their own information. But if a User belongs to “Company Administrator” role, he has administrator permissions and can read and write objects of other users as well. So how can application developers just depend on the Access Checks put into place in AAD Graph rather than enforcing them in their application when accessing AAD data? This is where OAuth 2.0 Authorization code grant will help us build an application using delegated access to the directory resources.
Overview of the PHP Sample
The functionality provided by the PHP sample is very limited. The goal is to show how Authorization Code can be used to access AAD Graph and so the application does not do much beyond that. The first thing the application asks the customer to do is to authorize via the AAD portal. Typically the application would authenticate the user via WS-Fed or SAML protocol but to make things simple, the sample application directly takes user to authorization. Once authorized, user is redirected to a page showing his/her details. There is an Edit link at the bottom of this page. You can only use this link if you have are using Administrator credentials while authorizing the application. And this access check is not done by the application but by the Graph API. Here is a brief description of the files that are part of this sample.
- Authorize.php: It’s the home page of the application and redirects the user to the AAD portal for retrieving authorization code.
- HandleAuthorizationResponse.php: The page handles the redirect from the AAD authorize page after the user authorizes.
- AuthorizationHelperForGraph.php: Takes care of putting together the URL for retrieving the authorization code and also getting the access token for accessing Graph using the authorization code fetched.
- GraphServiceAccessHelper.php: Takes care of putting together the HTTP requests to the Graph service and handling the JSON response.
- Settings.php: This file contains the constant values for clientId, Password, RedirectURI etc. that need to be updated to match the service principal you create (explained in the next section).
Setting up permissions
The previous steps below are now replaced using the Windows Azure Management Portal: https://manage.windowsazure.com/ Login to your Azure AD company, from this portal, and select "Add an application you're developing"
Next, select the type of App that you're developing - select Web Application and give it a friendly name, advance to the next step.
On step 2, add your App properties - the Sign-on URL will not be used in the PHP demo app, so set to any value. The App ID URI is a unique identifier for the app, and will be used in the PHP app's config file later.
Next configure permissions - for this demo, select the 3rd option Single Sign-on, Read and Write Directory Data. Select the check mark to finish the initial application configuration.
From the main Azure AD management portal, select "Applications" from the top menu bar. Find your application and select it.
From the Application page, Expand the section "Enable your app to read or write directory data", and select the Configure Key link,
You should now see the Configure page similar to the one shown below.
On the Configure App page:
1. Write down the Client ID value - this is the application ID, and will be used in the settings.php of the PHP app ($clientId variable).
2. Under the keys section, select a key duration (1 or 2 year) - the key value will be displayed after you select Save at the end. The key value will be used in the settings.php file ($password variable)
3. in the Reply Url section - enter https://localhost:9485/HandleAuthorizeResponse.php - this is the URL that the Authorization endpoint will redirect to, after the user successfully authenticates. This should be equal to the $ridrectUri value in the settings.php file.
4. Under Web apis - select "Windows Azure AD Graph" from the drop down menu - in the settings.php file, the value of the $resourceUri is "https://graph.windows.net", which is the WIndows Azure AD Graph Uri.
5. Select the Save button on the bottom.
After successfully saving the configuration, the key value should be displayed under keys - please record and save this value in a safe location. This key value cannot be retrieved after exiting this page. As mentioned in the above step, the key value is used for $clientId value in the settings.php file.
Your App configuration is now complete on the Azure AD side, now update the PHP sample app's settings.php values to match your configuration - Note: you will also need to add your tenant's name in the $appTenantDomainName variable in the settings.php file - this can be any domain owned by your tenant.
Below this line was the original, out of date instructions on Application Configuration.
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Steps to setting up permissions for application:
- Go to https://graphexplorer.cloudapp.net/
- Click the “Sign In” link on the right top hand corner.
- Sign in using admin credentials for your AAD tenant.
- Click the “Add Application Permission” link on the top.
- You can choose an existing client application or create a new client application. Let’s create a new client application.
- Choose any “Client APP Display Name” of your choice.
- Choose a “Client APP URL” that’s unique with in your tenant and maps to the address of your application. You can choose something like https://localhost:44305 while you are developing the application and replace 44305 with the port that your application is using.
- For the Service, select the “Microsoft.Azure.ActiveDirectory” from the dropdown. This service will exist in every tenant and represents nothing but AAD itself. We are trying to building an application that accesses AAD and thus AAD is the resource for us.
- For Scope, enter the name of any well-known role name in Azure Active directory. There are 3 roles in particular that are interesting when talking about application permissions:
- Directory Readers: Provides Read permission.
- Directory Writers: Provides Read+Write access but no Delete permissions.
- Company Administrator: Full admin permissions including deletes.
- Uncheck the “Public Client” check box since we are creating a web application. If we were building a native application like a windows store application, we would choose “Public Client”.
- Enter a password.( only needed for Private client)
- Click “Create Permission” which will display the “Client Id” and “Credentials” which you need to copy and paste in the Settings.PHP file of the PHP sample.
This is how the form looks before clicking “Create Permission”.
Once you click the “Create permission” button, Graph explorer will create the permission and show you the Client Id, App URL, Credentials Key for the Client application. Copy these values to settings.php file in the sample. App Url is called redirectURI in the application and Credentials Key is called password.
Getting an Authorization code
Now that the permission object has been set up, we can proceed to access Graph from our Application. The first thing we need to do is access the Authorization end point and get the authorization code. The end point for Authorization is: https://login.windows.net/common/oauth2/authorize . We need to specify the Application Id for the client application, application URI for the resource (in our case Graph) and the redirect URI we had specified while creating the Service Principal. The user will be redirected to the Azure AD login page and the user will be redirected back to the Redirect URI we specified in the request parameter after a successful login. The redirect URL will have the Authorization code. The sample response shown below is the redirect request to the application after a successful login. The client_id and redirect_uri in the request below comes from the above step when you created permission for this application.
Request URL:
Request Parameters:
response_type code |
client_id 599cea60-a2ba-4f9b-8f06-9f92986560f1 |
resource https://graph.windows.net |
redirect_uri https://localhost:9385/HandleAuthorizeResponse.php |
|
HTTP Method: GET
Response:
Getting an Access token with Auth Code
We can now use the Authorization code in conjunction with the client application Id, client Application Secret etc. to fetch the Access token. The Access token can be used to access the data of the tenant and the permissions that the App gets will be based on the role that the User belongs to and the Role that was used in Scope parameter when creating the Permission object for this application. The client_id and client_secret are the values from the Graph explorer when we created permission for this application.
Request URL:
Request Parameters:
grant_type |
authorization_code |
client_id |
599cfa60-a2ba-4f9b-8f06-9f92986560f1 |
redirect_uri |
|
client_secret |
DhjYU…kqqyHiqNm/PY= |
Code |
AAAAAAA…zS |
HTTP Method: GET
Response:
{ "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2CzkwXeiVQ", token_type":"Bearer", "expires_in":"28799", "expires_on":"1368676551", "refresh_token":"AAAAAAAADENAfM5UpyznQ8EHSHp0GI8GTGXonaBFZHZADR1Kf...-Q9SAA", "scope":"62e90394-69f5-4237-9190-012177145e10" } |
You can use access token in the response to talk to Graph by providing in the Authorization header(Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhb…….. VQ). The sample application does not login the user and stores a profile locally but a lot of real world application may want to do that in which case you can go back and fetch the access token without user interaction by using the refresh_token value in the response. The next section explains how to get an access token using a refresh token.
Getting an Access token with Refresh token
Request URL:
Request Parameters:
grant_type |
refresh_token |
client_id |
599cea60-a2ba-4f9b-8f06-9f92986560f1 |
|
|
client_secret |
DhjYUdb4PHA…..PY= |
refresh_token |
AAAAAAAAD…..A |
HTTP Method: GET
Response:
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2CzkwXeiVQ", token_type":"Bearer", "expires_in":"28799", "expires_on":"1368676551", "refresh_token":"AAAAAAAADENAfM5UpyznQ8EHSHp0GI8GTGXonaBFZHZADR1Kf...-Q9SAA", "scope":"62e90394-69f5-4237-9190-012177145e10" } |
Accessing information of the user from AAD using Graph
So the user has authenticated to the application and we have the access token to access Graph. But how do we get the information about the currently authorized user. It’s really simple with the new functionality that just got added in the Graph service. You can refer to the current user using the “me” alias. So the following URL can be used to get all the groups and roles that the user is memberOf: https://graph.windows.net/me/isMemberOf?api-version=2013-11-08 . Graph will figure out the user information from the claims in the token. The PHP application just displays the information regarding the user and thus does the following query to the graph: https://graph.windows.net/me?api-version=2013-11-08 and provides the token retrieved previously from token end point in Authorization Header. Apart from the “me” alias, “myorganization” alias was also added recently to Graph and refers to the tenant associated with the currently authenticated user or application trying to access graph. So you can use the following query to get all users for the tenant: https://graph.windows.net/myorganization/users?api-version=2013-11-08 .
As always, feedback and questions are welcome.
Comments
Anonymous
August 05, 2013
The comment has been removedAnonymous
September 04, 2013
After getting the auth-token I tried to get theinformation of the current user through the 'me' alias as described in the article.https://graph.windows.net/meThis does NOT work. It is returning the following error{ "Status Code" : "Unauthorized", "Description" : "The remote server returned an error: (401) Unauthorized.", "Response" : "{"odata.error":{"code":"Authentication_MissingOrMalformed","message":{"lang":"en","value":"Access Token missing or malformed."}}}"}I am using the correct auth-token. All other endpoints are working. Only the 'me' alias is not working. How is it possible then to get the information of the currently logged in users.Anonymous
September 17, 2013
Hi,Is it possible to have sign-out functionality in 3-legged authentication?if yes could you please provide me with more details.Anonymous
September 24, 2013
How can we logout form these authentications. Please provide me the code.Anonymous
March 19, 2014
Last month, I followed the settings of getting an authorization code, it worked. However, I added a new WAAD app this week and reconfigured my web app code, I got "TokenError: ACS70003: The access grant 'authorization_code' is not supported.", I have setup my application permission as following:Windows Azure Active Directory-Read and write directory data-Read directory data-Access your organization's directory (preview)-Enable sign-on and read users' profiles (preview).How can I fix it? Thanks!Anonymous
March 19, 2014
Hello Hsiung, I apologize if this has caused you problems - there is a known issue with new WAAD app registrations - we are working on a fix, which should be out shortly, and things should work as expected after that. Please retry in about day or two, and reply back to this if things are still not working. .Anonymous
March 23, 2014
Hi Edward, thank you for the reply!I create a new WAAD App today and connected my web app to it, but I still got the error 'ACS70003'.Is this caused by the issue?Anonymous
March 24, 2014
Looks like authorization flow is broken. You can still use "grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET", but that's very un-satisfying since I'd like my user to authorize the app.Can anyone point me where I can log a bug?Anonymous
March 26, 2014
Hi Vlad,I cannot set the grant_type to client_credentials, since I need to get current user profile by 'me' API, that would result in odata.error:" Resource not found for the segment 'me'".Is this ACS70003 error caused by system bug or my AD App setting? Thanks for your patience!Anonymous
April 05, 2014
Hi Guys,I'm getting exactly the same error - ACS70003 'authorization_code' is not supported. I registered my app in WAAD two days ago. So I suppose the bug is not fixed yet? If not, when should we expect it to be fixed? Or am I doing something wrong? Thanks.Anonymous
April 14, 2014
Hi Guys,Still ACS70003 'autorization_code is not supported' bug is not fixed. Not sure when it will be fixedAnonymous
April 16, 2014
+1 for a fix to the "ACS70003 'authorization_code' is not supported" issueAnonymous
May 07, 2014
I've hit the "ACS70003: The access grant 'authorization_code' is not supported" issue as well. Any fix? Or is there some configuration parameter that I missed?Anonymous
May 15, 2014
Any update from someone at Microsoft on this?Anonymous
May 18, 2014
according to this document msdn.microsoft.com/.../dn151791.aspx (open it then search "grant_type"), we can only use client_credentials now. And I think there is no /Me API anymore, so here is my solution for my application:use WS-Federation sign in and gain user idauthenticate against OAuth 2 with client_credentials, get access_token use the id and access_token to query Graph API to get current user profile. my application is a practice, that is why I have to do the step 3, if you just need to allowed user to sign in and get user profile, you only need to use WS-Federation to achieve that.Anonymous
June 29, 2014
You can refer to the current user using the “me” alias.Why 'me' alias gone away? We really need that.Anonymous
December 04, 2014
Hi. I'm having the same problems as others have mentioned with the "Access Token missing or malformed." message when tying to get user information. Any help on this would be really appreciated.Anonymous
December 28, 2014
It seems the bug related to "ACS70003 'authorization_code' is not supported" is still relevant. It is a shame it is not fixed for so long !!!Anonymous
October 25, 2015
How to get authorize code with out ms login UI? Is it possible?