-
Notifications
You must be signed in to change notification settings - Fork 0
Get an access token via Device Code flow
Support for the Device Code flow is new to MSGraphPSEssentials' New-MSGraphAccessToken
function. It enables us to initiate an access token request in PowerShell, requesting the specific API permissions we need for a given task at hand, and then manually use a web browser to complete the authorization process by entering a code at either https://microsoft.com/devicelogin (for Work/School accounts) or https://microsoft.com/link (for Personal Microsoft Accounts (MSA)). Once complete, back in PowerShell we receive the token.
In case we're setting up an unattended solution, we can obtain a refresh token along with the access token and later exchange the refresh token for a new access token, and a new refresh token. As long as the refresh token is never revoked, we could theoretically have this recurring renewal process automated without interruption forever (or at least as long as we need).
To start, install MSGraphPSEssentials as follows:
Install-Module MSGraphPSEssentials -Scope CurrentUser
If this is the first time you've installed a module this way, you'll need to confirm a couple of prompts. I'm purposely used -Scope CurrentUser
to avoid you needing admin privileges here.
Next, we will need an App Registration setup in Azure AD. For this task, you need to at least have the Application Administrator Azure AD role assigned. In the Azure AD Portal, navigate to Azure Active Directory > App Registrations and select New registration. At this point, we have two decisions to make:
-
We need to give the app a name. This can be anything, but should likely be something that describes the purpose of this app well, for example "MS Graph PS Automation".
-
We need to specify what kinds of accounts will be able to sign into this app. We're not really creating a true application here, we're just using this App Registration in Azure AD as a way to enable ourselves to authenticate in PowerShell using OAuth 2.0, where everything logging in is an application (public (interactive) or confidential (non-interactive/unattended)). We have the following options:
Who can use this application or access this API?
- Accounts in this organizational directory only (jb365 only - Single tenant)
- Accounts in any organizational directory (Any Azure AD directory - Multitenant)
- Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)
- Personal Microsoft accounts only
It really depends on what you plan on doing. For example, if we intend to use the EWS Managed API, I can tell you for certain, it's not possible to authenticate the EWS Managed API to Outlook.com accounts using OAuth, so we would pick between the first two options for that. However, if we were hoping to do things with Outlook.com, or OneDrive, using Microsoft Graph specific methods, any of the four options might be the right one - it's totally up to you.
Once the app has been registered/saved, we have two more steps to complete. After choosing the sign-in audience and saving, you should have ended up on the app's Overview page. While on the Overview page, make note of the Application (client) ID, as we'll use this shortly. From there, navigate to the Authentication menu item. In here we need to "Add a platform", then choose Mobile and desktop applications, and then check the box for the top-most default Redirect URI (https://login.microsoftonline.com/common/oauth2/nativeclient). You could get away with choosing other options for platforms and redirect URI's, however the Mobile/desktop application type and the default redirect URI are good safe bets for this PowerShell-exclusive use case. The second and final thing we need to do, still while within the Authentication menu, scroll down and set Allow public client flows to Yes. This is necessary for the Device Code flow to be possible.
At this point we are ready to test out the Device Code flow. I'll use some Outlook and OneDrive API permissions to demonstrate. First, I'll show how we might do this if we are targeting Personal accounts exclusively:
$DevToken = New-MSGraphAccessToken -ApplicationId <new app's ID> -Scopes Mail.ReadWrite, Files.ReadWrite, offline_access -Endpoint Consumers
Follow the instructions, which should look similar to this:
Authorization started (expires at 2020-12-23 09:32:24 PM)
To sign in, use a web browser to open the page https://www.microsoft.com/link and enter the code 6DS92SDB to authenticate.
[D] Done [?] Help (default is "D"):
The reason we see the www.microsoft.com/link URL is that we specified the Consumers endpoint. This locks in on Personal accounts as our target audience. The reason we specified the offline_access
scope is that this is how we indicate we also would like a refresh token included with our access token.
Now I'll demonstrate another use case, let's say we need to create one or more SharePoint Online lists. For this, we know that only Work/School accounts apply, so we should go with the Organizations endpoint, or specify the exact TenantId for the SPO tenant we'll be working on:
Example 1:
$DevToken = New-MSGraphAccessToken -ApplicationId <new app's ID> -Scopes Sites.Manage.All -Endpoint Organizations
We'll now see the Work/School accounts device code link:
Authorization started (expires at 2020-12-23 09:40:21 PM)
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code RXGM9EE7Z to authenticate.
[D] Done [?] Help (default is "D"):
Example 2:
$DevToken = New-MSGraphAccessToken -ApplicationId <new app's ID> -Scopes Sites.Manage.All -TenantId Customer123Tenant.onmicrosoft.com
# or
$DevToken = New-MSGraphAccessToken -ApplicationId <new app's ID> -Scopes Sites.Manage.All -TenantId 2e979fd3-4791-475a-96f1-431bf853dca6
Same thing this time, we'll see the Work/School accounts device code link:
Authorization started (expires at 2020-12-23 09:47:47 PM)
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code FM3EFCVG3 to authenticate.
[D] Done [?] Help (default is "D"):
By default, the -Endpoint
parameter is set to use the Common endpoint. This endpoint works great for many scopes (i.e. API permissions), and will automatically connect our request to the necessary tenant. Sometimes however, it is necessary to explicitly target the Consumers endpoint, or the Organizations endpoint (or instead the specific tenant's ID). Not to fear, as if you happen to target the wrong endpoint, you'll get an error like this:
$DevToken = New-MSGraphAccessToken -ApplicationId <new app's ID> -Scopes Sites.Manage.All
Invoke-RestMethod : {"error":"invalid_scope","error_description":"AADSTS70011: The provided value for the input parameter 'scope' is not valid. The scope 'Sites.Manage.All' is not valid...
Since we know the Sites.Manage.All scope is accurate (just check here: https://docs.microsoft.com/en-us/graph/api/list-create?view=graph-rest-1.0&tabs=http), we can assume that this error means that the Common endpoint doesn't support this scope, and so we just retry the command using the -Endpoint Organizations
or -TenantId <tenant domain/ID>
options instead.
I hope you found this sample helpful, it was a lot of text, and no pictures. Sorry about that, and feel free to ask questions in the Discussions area.