Authentication in UWP Application - azure

We are planning to implement Windows 10 UWP Application. We would like to authenticate user while accessing API Services hosted in Cloud.
Previously, we used the Microsoft.IdentityModel.Clients.ActiveDirectory NuGet package for authenticating in windows store 8.1. How do we authenticate user in Windows UWP Applications? I think AAD code for Windows Store and Windows Phone is different, how can we leverage AAD library for Windows 10 UWP applications. I have heard of Token Broker Authentication Architecture. Will this work for Azure Active Directory in addition to Facebook, etc.?
Please let me know if there is a workaround for AAD library to work in both Phone and Store (i.e. Universal App).

If you have an Native App that wants to access an API on Azure and authenticate with oAuth you need to use "OAuth 2.0 Authorization Code Flow" as describe on https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-protocols-oauth-code/.
This requires that you both your native app and api in the Azure Directory.
In https://azure.microsoft.com/nl-nl/documentation/articles/active-directory-devquickstarts-windowsstore/ a sample is given of a UWP App that accesses the graph.microsoft.com API, but you can replace this by your own API.
Sander,
If this answers your question please tag is such so we can help others.

Let me explain the steps.
You can still use Active Directory Authentication Library
in the UWP Apps.
To do it you have to add NuGet package (I pasted the link above). Once you do it there are few steps to implement authentication in your app:
1) Store information needed for the authentication (for instance in the App.xaml.cs constructor):
var localSettings = ApplicationData.Current.LocalSettings;
localSettings.Values["ida:AADInstance"] = "https://login.windows.net/{0}";
localSettings.Values["ida:Tenant"] = "<<Name of your tenant here>>";
localSettings.Values["ida:ClientId"] = "<<Client ID Here>>";
localSettings.Values["ida:RedirectUri"] = "<<Redirect URI here>>";
localSettings.Values["ApiBaseAddress"] = "<<ID of Api Resource here>>";
localSettings.Values["ServiceAddress"] = "<<Address of your Api here>>";
Now write the code for authentication (this is helper class):
class ADContextHelper
{
ApplicationDataContainer _localSettings;
AuthenticationContext _authContext;
string _aadInstance;
string _tenant;
string _clientId;
Uri _redirectUri;
string _authority;
string _apiResourceId;
string _apiBaseAddress;
public ADContext()
{
_localSettings = ApplicationData.Current.LocalSettings;
configureSettings();
_authContext = new AuthenticationContext(_authority);
}
private void configureSettings()
{
_aadInstance = _localSettings.Values["ida:AADInstance"].ToString();
_tenant = _localSettings.Values["ida:Tenant"].ToString();
_clientId = _localSettings.Values["ida:ClientId"].ToString();
_redirectUri = new Uri(_localSettings.Values["ida:RedirectUri"].ToString());
_authority = String.Format(_aadInstance, _tenant);
_apiResourceId = _localSettings.Values["ApiResourceId"].ToString();
_apiBaseAddress = _localSettings.Values["ApiBaseAddress"].ToString();
}
public async Task<string> Authenticate()
{
AuthenticationResult authResult = await _authContext.AcquireTokenAsync(_apiResourceId, _clientId, _redirectUri);
//Here you retrieve the token:
var token = authResult.AccessToken;
return token;
}
}
At the end I also include code for logout - maybe you will want to include it:
public async Task<bool> Logout()
{
string requestUrl = "https://login.microsoftonline.com/" + _tenant + "/oauth2/logout?post_logout_redirect_uri=" + _redirectUri;
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
var response = await client.SendAsync(request);
}
I hope this will help you.

Related

How to authenticate our .NET console application against SharePoint online if we have `DisableCustomAppAuthentication` set to true

We have the following:-
SharePoint online tenant recently created
Windows server 2019
.NET console application which have some code that integrates with SharePoint online
The .NET console application runs on schedule basis using windows task scheduler.
now previously on old tenants i authenticate my code using this method by passing the ClientID and Client Secret:-
static void Main(string[] args)
{
string siteUrl = "https://***.sharepoint.com/sites/CustomerServiceKB/";
string clientId = "******";
string clientSecret = "*****";
using (ClientContext context = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(siteUrl, clientId, clientSecret))
{
but on our newly created tenant we can not authenticate our code using the above method, because we have the DisableCustomAppAuthentication set to true.. now we do not want to modify this property.
So our question is; if we have the DisableCustomAppAuthentication set to true (ans we do not want to set it to false), then how we can authenticate our console application? which is hosted inside our windows server and which runs on schedule basis using tasks scheduler ?
So the DisableCustomAppAuthentication property was brought in (and was set to true by default) to support the deprecation of the Azure Access Control Service (ACS). The modern way to authenticate custom apps in Sharepoint tenants is to register them in the Azure AD.
Before moving on, consider the pros and cons of switching to the new authentication scheme. Mainly, the ACS enables users to granularly control site-level permissions for the application authentication, but Azure AD app registration makes the set of running applications transparent to the administrators. If you want to stay with ACS, just set the DisableCustomAppAuthentication to false.
Now, if you decided to move on with registering the application in the Azure ID, here are the steps to follow:
Log in to the Azure portal and navigate to the Azure Active Directory.
Register the application in the Azure AD portal. Here's a guide on how to do it. Obtain the application (client) ID on the application overview page.
Set all the necessary permissions, confirm them as a global administrator (or ask the administrator for confirmation).
Configure the authentication. Choose the authentication option: whether you want the application to authenticate itself in the Microsoft IAM via a cryptographic certificate or a client secret.
Obtain your Azure Active Directory tenant ID (not to be confused with the Sharepoint Online tenant ID). Here's how to do in in the Azure AD; there's also a hacky way.
Now use the client ID (from step 2), the authentication option (step 4), and the AAD tenant ID (step 5) to authenticate and run your application:
using Microsoft.Identity.Client;
[..]
private static async Task<string> GetToken()
{
string applicationId = "client-id";
string tenantId = "aad-tenant-id";
bool isUsingClientSecret = <true or false>;
IConfidentialClientApplication app;
if (isUsingClientSecret)
{
string secret = "secret";
app = ConfidentialClientApplicationBuilder.Create(applicationId)
.WithClientSecret(secret)
.WithAuthority($"https://login.microsoftonline.com/{tenantId}")
.Build();
}
else
{
string certificateLocation = "certificate-file";
X509Certificate2 certificate = ReadCertificate(certificateLocation);
app = ConfidentialClientApplicationBuilder.Create(applicationId)
.WithCertificate(certificate)
.WithAuthority($"https://login.microsoftonline.com/{tenantId}")
.Build();
}
var scopes = new[] { "https://***.sharepoint.com/.default" };
var authenticationResult = await app.AcquireTokenForClient(scopes).ExecuteAsync();
return authenticationResult.AccessToken;
}
static async Task MainAsync(string[] args)
{
string site = "https://***.sharepoint.com/sites/CustomerServiceKB";
string token = await GetToken();
using (ClientContext context = new ClientContext(site))
{
context.ExecutingWebRequest += (s, e) =>
{
e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + token;
};
Web web = context.Web;
context.Load(web);
context.ExecuteQuery();
}
}
static void Main(string[] args)
{
try
{
AsyncContext.Run(() => MainAsync(args));
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
throw;
}
}

Unable to get the authentication token after redirecting to web app

I'm working on implementing integrating Azure AD login authentication to my web app. I have created an account in azure development portal and registered my app details.
my app URL -> https://my-sample-app/my.dashboard/
my redirect url is ->https://my-sample-app/my.dashboard/ws/aad/callback/
Note : ws that comes after my app url is the servlet adapter configured
my web app is a java app and i'm using ADAL java SDK
I have referred this article Authenticate to an Azure API App from Java and did the similar way
this is the code logic written under web path "aad/callback"
String appIdUri = System.getProperty("azure.app.id.uri", "https://login.microsoftonline.com/");
String authority = System.getProperty("azure.authority.url", "https://login.microsoftonline.com/my-sample-app.onmicrosoft.com");
String clientId = System.getProperty("azure.client.id", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
String clientSecret = System.getProperty("azure.client.secret", "xxxxxxxxxxxxxxxxxxxxxxxx");
AuthenticationContext context = null;
AuthenticationResult result = null;
ExecutorService service = null;
UserVO userVO = null;
try {
HttpsURLConnection conn = (HttpsURLConnection) new URL(appIdUri).openConnection();
service = Executors.newFixedThreadPool(1);
context = new AuthenticationContext(authority, false, service);
ClientCredential credential = new ClientCredential(clientId, clientSecret);
Future<AuthenticationResult> future = context.acquireToken(appIdUri, credential, null);
result = future.get();
HttpSession session = request.getSession();
LOGGER.info("session :{}",session);
String accessToken = null;
if (result == null) {
throw new ServiceUnavailableException("authentication result was null");
} else {
accessToken = result.getAccessToken();
}
String data = "{\"access_token\": \"" + accessToken + "\"}";
LOGGER.info("access_token :{}", data);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.addRequestProperty("Content-Length", data.length() + "");
new DataOutputStream(conn.getOutputStream()).writeBytes(data);
String authTokenResp = IOUtils.toString(conn.getInputStream());
Gson gson = new Gson();
Map<String, Object> map = gson.fromJson(authTokenResp, Map.class);
String authenticationToken = (String) map.get("authenticationToken");
System.out.println("Authentication Token: "+authenticationToken);
I'm able to see the access token value in the log statement but the authTokenResp output value that i received from authTokenResp = IOUtils.toString(conn.getInputStream()); looks like some html page (probably the login page response of portal.office.com ) doesn't has key authenticationToken in it.
I think I have made mistake by mentioning wrong URL for the appIdUri.
please can i someone tell me what URL should be given for appIdUri ? where can i find this URL value in azure portal ?
This sample is just a client credential flow to get access token.
please can i someone tell me what URL should be given for appIdUri ?
where can i find this URL value in azure portal ?
The first parameter of acquireToken method is the value of a resource which you want to access.It is the App ID URI of the target web API (secured resource). To find the App ID URI, in the Azure Portal, click Azure Active Directory, click Application registrations, open the application's Settings page, then click Properties. It may also be an external resource like https://graph.microsoft.com. This is required in one of either the authorization or token requests.
Is my-sample-app.onmicrosoft.com your tenant name?
String authority = System.getProperty("azure.authority.url", "https://login.microsoftonline.com/{your_tenant_name}");
If you want to integrate Azure AD login authentication to your web app, you should refer to this sample.

ADFS : Acquiring a Token programmatically

So we have built a set of Azure Functions that are secured by ADFS (MSAL)
We have configured an App in ADFS and got it all working well with our Android client.
We now want to do some API testing so we want to programmatically generate Auth tokens to test the API's
I can't get the following code to work at all, maybe I have the tenant ID wrong, in the App config, its a GUID (42b03d0b-d7f2-403e-b764-0dbdcf0505f6), but examples say it's our domain
string userName = "-";
string password = "-";
string clientId = "ee13c922-bf4b-4f0a-ba39-ea74e1203c6e";
var credentials = new UserPasswordCredential(userName, password);
var authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/acostaonline.onmicrosoft.com");
var result = await authenticationContext.AcquireTokenAsync("https://graph.windows.net", clientId, credentials);
UPDATE
So changed the code to be MSAL and still trying to login via username and password. Now it just times out
string authority = "https://login.microsoftonline.com/42b03d0b-d7f2-403e-b764-0dbdcf0505f6/";
string[] scopes = new string[] { "user.read" };
PublicClientApplication app = new PublicClientApplication("ee13c922-bf4b-4f0a-ba39-ea74e1203c6e", authority);
var accounts = await app.GetAccountsAsync();
Microsoft.Identity.Client.AuthenticationResult result = null;
if (accounts.Any())
{
result = await app.AcquireTokenSilentAsync(scopes, accounts.FirstOrDefault());
}
else
{
try
{
var securePassword = new SecureString();
foreach (char c in "PASSWORD") // you should fetch the password keystroke
securePassword.AppendChar(c); // by keystroke
result = await app.AcquireTokenByUsernamePasswordAsync(scopes, "AUSER#acosta.com",
securePassword);
}
}
Error
SocketException: A connection attempt failed because the connected
party did not properly respond after a period of time, or established
connection failed because connected host has failed to respond
172.26.200.77:443
It seems that the code you provided is using ADAL instead of MSAL.
The main difference is that with ADAL you would use an AuthenticationContext to acquire tokens, whereas in MSAL you use ConfidentialClientApplication or PublicClientApplication, depending on if the application is running in a back-end or on the user's device.
Here is the article about Differences between ADAL.NET and MSAL.NET applications.
When you use MSAL.Net to get a token for the Microsoft Graph API, you could use the following code:
public static PublicClientApplication PublicClientApp = new
PublicClientApplication(ClientId);
var app = App.PublicClientApp;
ResultText.Text = string.Empty;
TokenInfoText.Text = string.Empty;
var accounts = await app.GetAccountsAsync();
authResult = await app.AcquireTokenSilentAsync(_scopes, accounts.FirstOrDefault());
For more details, you could refer to this article, in left menu also includes Android and iOS.

How to call Microsoft Graph from console application c#

I need to call Microsoft Graph API to create user in Azure AD.
First I need to test from console application and then need to implement in Azure function.
https://developer.microsoft.com/en-us/graph/graph-explorer
I am new to Microsoft Graph API , How can I connect and execute API from c# console application.
I have already registered the application in AAD.
I am trying to acquire token as :
string resourceId = "https://graph.microsoft.com";
string tenantId = "<tenantID>";
string authString = "https://login.microsoftonline.com/" + tenantId;
string upn = String.Empty;
string clientId = "<ClientID>";
string clientSecret = "<clientSecret>";
//string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
log.Verbose("ClientSecret=" + clientSecret);
log.Verbose("authString=" + authString);
var authenticationContext = new AuthenticationContext(authString, false);
// Config for OAuth client credentials
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(resourceId,clientCred);
string token = authenticationResult.AccessToken;
log.Verbose("token=" + token);
I trying to use existing AADB2C.
b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.
I have enabled permission as:
I neither get exception nor get access token and program silently exit
Also :
There is new library
<package id="Microsoft.Identity.Client" version="1.1.0-preview" targetFramework="net46" />
How can I direct login without login pop-up with the following and acquire token ?
PublicClientApplication
I assume that you already have Azure AD application with granted Administrative Consent.
In order to connect from a console app, you'll need to first obtain a valid token. Since you lack a UI, you'll want to Get access without a user. Note that this type of "app-only" token requires Administrative Consent before it can be used.
Then you have to add two NuGet dependencies to your dotnet project
<PackageReference Include="Microsoft.Graph" Version="1.15.0" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.0.0" />
Microsoft.Identity.Client for authentication using Azure AD and Microsoft.Graph for executing MS Graph queries.
var tenantId = "you-azure-tenand-id";
var clientId = "azure-ad-application-id";
var clientSecret = "unique-secret-generated-for-this-console-app";
// Configure app builder
var authority = $"https://login.microsoftonline.com/{tenantId}";
var app = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))
.Build();
// Acquire tokens for Graph API
var scopes = new[] {"https://graph.microsoft.com/.default"};
var authenticationResult = await app.AcquireTokenForClient(scopes).ExecuteAsync();
// Create GraphClient and attach auth header to all request (acquired on previous step)
var graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(requestMessage => {
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("bearer", authenticationResult.AccessToken);
return Task.FromResult(0);
}));
// Call Graph API
var user = await graphClient.Users["Me#domain.com"].Request().GetAsync()
Update 2020.01
There is a new package Microsoft.Graph.Auth that simplify auth and token management.
Let's say you want to use some Beta API this time.
<PackageReference Include="Microsoft.Graph.Auth" Version="1.0.0-preview.2" />
<PackageReference Include="Microsoft.Graph.Beta" Version="0.12.0-preview" />
var tenantId = "you-azure-tenand-id";
var clientId = "azure-ad-application-id";
var clientSecret = "unique-secret-generated-for-this-console-app";
// Configure application
var clientApplication = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.WithClientSecret(clientSecret)
.Build();
// Create ClientCredentialProvider that will manage auth token for you
var authenticationProvider = new ClientCredentialProvider(clientApplication);
var graphClient = new GraphServiceClient(authenticationProvider);
// Call Graph API
var user = await graphClient.Users["Me#domain.com"].Request().GetAsync()
In order to connect from a console app, you'll need to first obtain a valid token. Since you lack a UI, you'll want to Get access without a user. Note that this type of "app-only" token requires Administrative Consent before it can be used.
In order to support the Create User scenario, you will need to ensure your permission scopes include User.ReadWrite.All.
Once you have a valid token you can make calls into the Graph API. Graph is a REST API so all calls are made over HTTP with the token passed within the Authorization Header.
You can read a general overview at Get started with Microsoft Graph and REST. There are also several language/framework specific overviews available but all of them assume you have a UI (i.e. not simply console). Generally speaking, if you're looking for a console tool for creating users you may prefer using PowerShell.
This question is rather old, but it was one of the first questions that popped up when I initially needed to do the same thing. Below I will document the steps and resources I used to make it happen:
I used an O365 tenant (you can get one from office.com - note that you can get a one year developer trial). Once you have a tenant, you also have access to Azure portal if you log in as your tenant admin user. Under Azure Portal, go to Active Directory/properties to see the tenant ID.
I followed the instructions here https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-netcore-daemon to create a new registered application. I created a new secret and copied the value (that will be client secret in your console app). The registered application id will be the client ID in your console app.
I cloned the github repo in the above link and changed the values in the appsettings to the tenant ID, client ID, and client secret noted in the steps above.
The code in that repo has some methods called which no longer exist in ConfigurationBuilder as of .NETCore 2.1. I substituted these lines (there's probably a better / shorter way):
authenticationConfig.Tenant = Configuration.GetSection("Tenant").Value.ToString();
authenticationConfig.ClientId = Configuration.GetSection("ClientId").Value.ToString();
authenticationConfig.ClientSecret = Configuration.GetSection("ClientSecret").Value.ToString();
You should now be iterating through users in your tenant. You can go to the graph explorer ( https://developer.microsoft.com/en-us/graph/graph-explorer ) to find more URLs (find the line in Program.cs to substitute them). As far as I know so far, v2.0 of the API is "beta" (put "beta" where "v1.0" is - someone please correct me if I'm wrong).
await apiCaller.CallWebApiAndProcessResultASync("https://graph.microsoft.com/v1.0/users", result.AccessToken, Display);
This MSAL console app tutorial describes getting a token using MSAL (Microsoft Authentication Library) in a .NET console app.
To make a Microsoft Graph call, I replaced the RunAsync() function
with this, which attaches the acquired token to the requests with the
GraphServiceClient:
static async Task RunAsync()
{
const string clientId = "your client id";
string[] scopes = { "User.Read" };
AuthenticationResult result;
var clientApp = new PublicClientApplication(clientId);
try
{
result = await clientApp.AcquireTokenAsync(scopes.Split(new char[] { ' ' }));
Console.WriteLine(result.AccessToken);
GraphServiceClient graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
// Append the access token to the request.
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", result.AccessToken);
// Some identifying header
requestMessage.Headers.Add("SampleID", "aspnet-connect-sample");
}));
// Get a page of mail from the inbox
var inboxMail = await graphClient.Me.MailFolders.Inbox.Messages.Request().GetAsync();
foreach(var mail in inboxMail.CurrentPage.ToList())
{
Console.Write("From: {0}\nSubject: {1}\nBody:\n{2}\n--------------------\n",
mail.From.EmailAddress.Address, mail.Subject, mail.BodyPreview);
}
}
// Unable to retrieve the access token silently.
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}

Sending IM with Skype for Business Online from Console App

I am trying to set up a C# console app that can send notifications/reminders to users via Skype for Business online from a generic AD account. I was excited to see the other day that according to this page, UCWA is now supported in Skype for Business online: https://msdn.microsoft.com/en-us/library/office/mt650889.aspx.
I've been trying to follow this tutorial to get this set up: https://msdn.microsoft.com/en-us/library/office/mt590891(v=office.16).aspx. So far I haven't really had much luck... I have my application set up in Azure AD but I get stuck at the "Requesting an access token using implicit grant flow" step of that article (not 100% certain I'm taking the correct actions before that either)... so far I have this:
string clientId = "xxxxxxxx"
string resourceUri = "https://webdir.online.lync.com";
string authorityUri = "https://login.windows.net/common/oauth2/authorize";
AuthenticationContext authContext = new AuthenticationContext(authorityUri);
UserCredential cred = new UserCredential("username", "password");
string token = authContext.AcquireToken(resourceUri, clientId, cred).AccessToken;
var poolReq = CreateRequest("https://webdir.online.lync.com/autodiscover/autodiscoverservice.svc/root", "GET",token);
var poolResp = GetResponse(poolReq);
dynamic tmp = JsonConvert.DeserializeObject(poolResp);
string resourcePool = tmp._links.user.href;
Console.WriteLine(resourcePool);
var accessTokenReq = CreateRequest("https://login.windows.net/common/oauth2/authorize"
+ "?response_type=id_token"
+ "&client_id=" + clientId
+ "&redirect_uri=https://login.live.com/oauth20_desktop.srf"
+ "&state=" + Guid.NewGuid().ToString()
+ "&resource=" + new Uri(resourcePool).Host.ToString()
, "GET",token);
var accessTokenResp = GetResponse(accessTokenReq);
my GetResponse and CreateRequest methods:
public static string GetResponse(HttpWebRequest request)
{
string response = string.Empty;
using (HttpWebResponse httpResponse = request.GetResponse() as System.Net.HttpWebResponse)
{
//Get StreamReader that holds the response stream
using (StreamReader reader = new System.IO.StreamReader(httpResponse.GetResponseStream()))
{
response = reader.ReadToEnd();
}
}
return response;
}
public static HttpWebRequest CreateRequest(string uri, string method, string accessToken)
{
HttpWebRequest request = System.Net.WebRequest.Create(uri) as System.Net.HttpWebRequest;
request.KeepAlive = true;
request.Method = method;
request.ContentLength = 0;
request.ContentType = "application/json";
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken));
return request;
}
accessTokenResp is an office online logon page, not the access token I need to move forward... so I'm stuck. I've tried quite a few variations of the above code.
I've been scouring the net for more examples but can't really find any, especially since UCWA support for Office 365 is so new. Does anyone have an example of how to do what I am trying to do or can point me to one? Everything I've found so far hasn't really even been close to what I'm trying. I can't use the Skype for Business client SDK unfortunately either as it doesn't meet all of my requirements.
I came to a working solution using ADAL (v3), with the help of steps outlined at
Authentication using Azure AD
Here the steps, which involve requesting multiple authentication tokens to AAD using ADAL
Register your application, as Native Application, in Azure AD.
Perform autodiscovery to find user's UCWA root resource URI.
This can be done by performing a GET request on
GET https://webdir.online.lync.com/Autodiscover/AutodiscoverService.svc/root?originalDomain=yourdomain.onmicrosoft.com
Request an access token for the UCWA root resource returned in the autodiscovery response, using ADAL
For instance, your root resource will be at
https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
you'll have to obtain a token from AAD for resource https://webdir0e.online.lync.com/
Perform a GET on the root resource with the bearer token obtained from ADAL
GET https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
This will return, within the user resource, the URI for applications resource, where to create your UCWA application. This in my case is:
https://webpoolam30e08.infra.lync.com/ucwa/oauth/v1/applications
Residing then in another domain, thus different audience / resource, not included in the auth token previously obatained
Acquire a new token from AAD for the host resource where the home pool and applications resource are (https://webpoolam30e08.infra.lync.com in my case)
Create a new UCWA application by doing a POST on the applications URI, using the token obtained from ADAL
Voilá, your UCWA application is created. What I notice at the moment, is that just few resources are available, excluding me / presence. So users' presence can be retrieved, but self presence status can't be changed.
I've been able however to retrieve my personal note, and the following resources are available to me:
people
communication
meetings
Show me some code:
Function to perform the flow obtaining and switching auth tokens
public static async Task<UcwaApp> Create365UcwaApp(UcwaAppSettings appSettings, Func<string, Task<OAuthToken>> acquireTokenFunc)
{
var result = new UcwaApp();
result.Settings = appSettings;
var rootResource = await result.Discover365RootResourceAsync(appSettings.DomainName);
var userUri = new Uri(rootResource.Resource.GetLinkUri("user"), UriKind.Absolute);
//Acquire a token for the domain where user resource is
var token = await acquireTokenFunc(userUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped));
//Set Authorization Header with new token
result.AuthToken = token;
var usersResult = await result.GetUserResource(userUri.ToString());
//
result.ApplicationsUrl = usersResult.Resource.GetLinkUri("applications");
var appsHostUri = new Uri(result.ApplicationsUrl, UriKind.Absolute).GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
//Acquire a token for the domain where applications resource is
token = await acquireTokenFunc(appsHostUri);
//Set Authorization Header with new token
result.AuthToken = token;
//
var appResult = await result.CreateApplicationAsync(result.ApplicationsUrl, appSettings.ApplicationId, appSettings.UserAgent, appSettings.Culture);
return result;
}
Usage code ato retrieve OAuth tokens using ADAL
var ucSettings = new UcwaAppSettings
{
UserAgent = "Test Console",
Culture = "en-us",
DomainName = "yourdomain.onmicrosoft.com",
ApplicationId = "your app client id"
};
var acquireTokenFunc = new Func<string, Task<OAuthToken>>(async (resourceUri) =>
{
var authContext = new AuthenticationContext("https://login.windows.net/" + ucSettings.DomainName);
var ar = await authContext.AcquireTokenAsync(resourceUri,
ucSettings.ApplicationId,
new UserCredential("myusername", "mypassword"));
return new OAuthToken(ar.AccessTokenType, ar.AccessToken, ar.ExpiresOn.Ticks);
});
var app = await UcwaApp.Create365UcwaApp(ucSettings, acquireTokenFunc);
It should be of course possible to avoid hard-coding username and password using ADAL, but this was easier for PoC and especially in case of Console Application as you asked
I've just blogged about this using a start-to-finish example, hopefully it will help you. I only go as far as signing in, but you can use it with another post I've done on sending IMs using Skype Web SDK here (see day 13 and 14) and combine the two, it should work fine.
-tom
Similar to Massimo's solution, I've created a Skype for Business Online C# based console app that demonstrates how to sign and use UCWA to create/list/delete meetings and change user presence. I haven't gotten around to extending it to send IM's, but you're certainly welcome to clone my repository and extend it to your needs. Just drop in your Azure AD tenant name and native app ID into the code.
I think they just turned this on today - I was doing something unrelated with the Skype Web SDK samples and had to create a new Azure AD app, and noticed that there are two new preview features for receiving conversation updates and changing user information.
Now everything in the Github samples works for Skype For Business Online.

Resources