Uncategorized

Trusted Application API (Skype for Business) – Authentication and Online Meetings

[Note (Dec 2018)] Use new Teams calling API for advanced interactive applications. (This post is old.)

 

Programming for Trusted Application API (added table of contents…)

Skype for Business Development Platform provides the various developer experiences, but there’s been no way to develop server-side application with online SKUs for a long time. (With server SKUs, you can use existing UCMA for the server-side endpoint programming.)
Now you can use the Trusted Application API for this sort of server-side development with Office 365.  (Now in preview.)

This brand-new Trusted Application API covers the following server-side (backend) scenarios for developers. (See “MSDN : Trusted Application API” for details.)
Especially, you can assign the PSTN phone number to this trusted endpoint, and then you can provide the telephony solutions like IVR (Interactive Voice Response) for all users who is not having the Skype client.
Trusted Application API is not just for the bot, but including a lot of server-side powerful scenarios.

  • Bots and Notifications
  • Anonymous Customer Web Chat
  • PSTN audio conferencing
    (IVR to join the conference, in-meeting Personal Virtual Assistant, and in-meeting announcements)
  • Service-side meeting recording
  • Inbound/outbound IVRs
  • Helpdesk
  • Expert-finder
  • Customer engagement / Contact Center

Note : Several scenarios are not available in current preview (Feb 2017).

In this post, we focus on the authentication and online meetings for your first start.
Later I will show you the simple programming code with SDK, but first let’s look at the quick view of HTTP flows, because it helps you understand how it works on the bottom and trouble-shootings.

Endpoint Registration

Before building your applications, you must register your app (endpoint) in Azure AD (Azure Active Directory) and Skype for Business Online Trusted Application platform.

First you should go to Skype for Business Online Application Registration Portal, login with Office 365 admin account, fill the settings, and create your application. This application is registered in your Azure AD tenant. (You can see the registered application in Azure Portal without Azure subscription.)

Trusted Application API uses the application context token instead of the user context (see “Azure AD – Backend server-side application” in my early post). Then please select the appropriate application permissions (not delegated permissions) according to your application’s functionalities in the portal. (see the following screenshot)
For example, if your application handles the online meeting capabilities, select only [Create on-demand Skype meetings], [Join and Manage Skype Meetings], and [Guest user join services] in Application Registration Portal.

After you created, please copy the generated application id and client secret (key).

Note that you must create (or setup) your application using Skype for Business Online Application Registration Portal, not using Azure Portal. If you have already registered your application with Azure Portal, make sure to set up with Skype for Business Online Application Registration Portal again. (see the following screenshot)
Because the application must be stored in Skype for Business Online platform.

After you complete the application registration, you must access the following url with your Office 365 administrator account, and consent this application as administrator.
Please replace the following {application id} and {sign-on url} for your appropriate values. (Note that the all values must be url-encoded.)
As you can see, the resource id of Trusted Application API is https://noammeetings.resources.lync.com .

https://login.windows.net/common/oauth2/authorize?response_type=id_token
  &client_id={application id}
  &redirect_uri={sign-on url}
  &response_mode=form_post
  &nonce=123456
  &resource=https%3A%2F%2Fnoammeetings.resources.lync.com
  &prompt=admin_consent

When you login with admin account, the following consent UI is displayed. Please accept this consent.

Next you must register the trusted application endpoint in your Skype for Business Online Trusted Application platform.
Before doing that (registration), please download and install Skype for Business Online Windows PowerShell Module in your Windows client beforehand.

After the installation is done, launch PowerShell and run the following commands.

$cr = Get-Credential
# It prompts login. Enter your admin user id and password.
$session = New-CsOnlineSession -Credential $cr
Import-PSSession $session
New-CsOnlineApplicationEndpoint `
  -Uri "sip:{arbitrary unique name}@{your domain prefix}.onmicrosoft.com" `
  -ApplicationId "{application id}" `
  -Name "{your app name}" `
  -Tenant "{your tenant id}"

# If you get tenant id, please input the following
# $tenantId = (Get-MsolCompanyInformation).objectId
# echo $tenantId

Here’s my example.

$cr = Get-Credential
# It prompts login. Enter your admin user id and password.
$session = New-CsOnlineSession -Credential $cr
Import-PSSession $session
New-CsOnlineApplicationEndpoint `
  -Uri "sip:trustedapidemo01@mod776816.onmicrosoft.com" `
  -ApplicationId "d4daaf71-5f06-4f70-bf4b-418a97f34741" `
  -Name "TrustedApiTest01" `
  -Tenant "3bc5ea6c-9286-4ca9-8c1a-1b2c4f013f15"

As I described earlier, you can assign PSTN phone number to trusted endpoint, but here I skip this step.

Note : You can also remove (Remove-CsOnlineApplicationEndpoint) and modify (Set-CsOnlineApplicationEndpoint) the trusted endpoint by PowerShell.

Authentication and Initialization

Trusted Application API uses the application context token, not user context token. As I explained in my early post “Azure AD – Backend server-side application“, no interactive UI is needed for retrieving token.
We can get the application context token (access token) for the Trusted Application API (https://NOAMmeetings.resources.lync.com) with only application id and secret. (See the following HTTP request.)
Note that you need the tenant-aware uri (https://login.microsoftonline.com/{your tenant realm}/oauth2/token) as follows.

POST https://login.microsoftonline.com/mod776816.onmicrosoft.com/oauth2/token
Accept: application/json
Content-Type: application/x-www-form-urlencoded

resource=https%3A%2F%2FNOAMmeetings.resources.lync.com&
client_id=d4daaf71-5f06-4f70-bf4b-418a97f34741&
client_secret=kEQ2B1rCs...&
grant_type=client_credentials
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "token_type": "Bearer",
  "expires_in": "3600",
  "ext_expires_in": "262800",
  "expires_on": "1492076011",
  "not_before": "1492072111",
  "resource": "https://NOAMmeetings.resources.lync.com",
  "access_token": "eyJ0eXAiOi..."
}

After you’ve got access token, first we ask for the trusted endpoint url using the discovery service. (See the following HTTP request.)
You must set the retrieved access token in HTTP header as follows.

GET https://api.skypeforbusiness.com/platformservice/discover
Authorization: Bearer eyJ0eXAiOi...
Accept: application/json; charset=utf-8
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "_links": {
    "self": {
      "href": "https://api.skypeforbusiness.com:4443/platformservice/discover"
    },
    "service:applications": {
      "href": "https://ring2noammeetings.resources.lync.com/platformService/v1/applications"
    },
    "myApplications": {
      "href": "https://ring2noammeetings.resources.lync.com/platformService/v1/myApplications"
    }
  },
  "rel": "service:discover"
}

Next you get the access url for your sip application (sip:{unique name}@{your domain prefix}.onmicrosoft.com) as follows.
Please replace endpointId with your app’s sip id.

GET https://ring2noammeetings.resources.lync.com/platformService/v1/applications?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com
Authorization: Bearer eyJ0eXAiOi...
Accept: application/json; charset=utf-8
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "_links": {
    "self": {
      "href": "/platformservice/v1/applications"
    },
    "service:application": {
      "href": "/platformservice/v1/applications/3877116191?endpointId=sip%3atrustedapidemo01%40mod776816.onmicrosoft.com"
    }
  },
  "rel": "service:applications"
}

Next you retrieve all endpoints for each resources (resources for ad-hoc meeting, anonymous joining token, messaging, etc) as follows.

For example, if your app want to create new ad-hoc meeting, use the following /platformservice/v1/applications/3877116191/adhocMeetings .

GET https://ring2noammeetings.resources.lync.com/platformservice/v1/applications/3877116191?endpointId=sip:trustedapidemo01%40mod776816.onmicrosoft.com
Authorization: Bearer eyJ0eXAiOi...
Accept: application/json; charset=utf-8
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "_links": {
    "self": {
      "href": "/platformservice/v1/applications/3877116191?endpointId=sip%3atrustedapidemo01%40mod776816.onmicrosoft.com"
    },
    "service:anonApplicationTokens": {
      "href": "/platformservice/v1/applications/3877116191/anonApplicationTokens?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
    }
  },
  "_embedded": {
    "service:communication": {
      "_links": {
        "self": {
          "href": "/platformservice/v1/applications/3877116191/communication?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
        },
        "service:joinOnlineMeeting": {
          "href": "/platformservice/v1/applications/3877116191/communication/onlineMeetingInvitations?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
        },
        "service:inviteUserToMeeting": {
          "href": "/platformservice/v1/applications/3877116191/communication/userMeetingInvitations?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
        },
        "service:startMessaging": {
          "href": "/platformservice/v1/applications/3877116191/communication/messagingInvitations?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
        },
        "service:startAudioVideo": {
          "href": "/platformservice/v1/applications/3877116191/communication/audioVideoInvitations?modalities=AudioVideou0026endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
        },
        "service:startAudio": {
          "href": "/platformservice/v1/applications/3877116191/communication/audioVideoInvitations?modalities=Audiou0026endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
        }
      },
      "rel": "service:communication",
      "etag": "4294967295"
    },
    "myOnlineMeetings": {
      "_links": {
        "self": {
          "href": "/platformservice/v1/applications/3877116191/myOnlineMeetings?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
        }
      },
      "rel": "myOnlineMeetings"
    },
    "service:adhocMeetings": {
      "_links": {
        "self": {
          "href": "/platformservice/v1/applications/3877116191/adhocMeetings?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
        }
      },
      "rel": "service:adhocMeetings"
    }
  },
  "rel": "service:application"
}

Sample – Interact with Adhoc Online Meeting

The schema of Trusted Application endpoint is based on existing UCWA schema. If you’re familiar with UCWA, you can easily understand the envelop of trusted application’s HTTP flow.
As I mentioned before, there are many scenarios (bot, IVR, call bridge, etc) for trusted api, and let’s see the simple ad-hoc meeting example here.

Skype for Business developer platform is providing the B2C scenario like “staff-customers”, “doctor-patients”, or “lawyer-clients” using the Skype guest online meeting join. (See the document of Skype for Business App SDK or Skype Web SDK in MSDN.)
In this scenario, the application must provide the following steps.

  • When it’s called, the application creates the ad-hoc meeting in the backend.
  • The staff joins in this generated meeting as Skype users with Skype client or Skype Web SDK etc.
  • On the other hand, the customer joins as the guest account (as anonymous user) without Skype license. The application must provide the token for anonymous join, and Skype Web SDK / Skype for Business App SDK will provide the user interface for customers. (They don’t have Skype client.)

As you can see, the backend api helps several tasks in this scenario. (For instance, creating ad-hoc meeting, providing the token for anonymous join, etc)
Now here I describe how you can leverage Trusted Application API along with this scenario.

For example, the following is creating new ad-hoc meeting with Trusted Application API. The uri fragment of /platformservice/v1/applications/3877116191/adhocMeetings is the previously retrieved uri.

The retrieved joinUrl is the meeting url. For instance, you can join the meeting by accessing this url with your Web browser.

POST https://ring2noammeetings.resources.lync.com/platformservice/v1/applications/3877116191/adhocMeetings?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com
Authorization: Bearer eyJ0eXAiOi...
Content-Type: application/vnd.microsoft.com.ucwa+json; charset=utf-8

{
  "subject": "meeting01",
  "accessLevel": "Everyone",
  "rel": "service:meeting"
}
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.com.ucwa+json; charset=utf-8
ETag: "4221088333"

{
  "accessLevel": "Everyone",
  "entryExitAnnouncement": "Disabled",
  "automaticLeaderAssignment": "Disabled",
  "description": "",
  "expirationTime": "/Date(1492106326000)/",
  "onlineMeetingId": "PYQC0NM0",
  "onlineMeetingUri": "sip:DM20R04meet1467@noammeetings.lync.com;gruu;opaque=app:conf:focus:id:PYQC0NM0",
  "organizerUri": "sip:DM20R04meet1467@noammeetings.lync.com",
  "conferenceId": "PYQC0NM0",
  "phoneUserAdmission": "Disabled",
  "lobbyBypassForPhoneUsers": "Disabled",
  "subject": "meeting01",
  "joinUrl": "https://meet.resources.lync.com/NOAMmeetings/dm20r04meet1467/PYQC0NM0",
  "_links": {
    "self": {
      "href": "/platformservice/v1/applications/3877116191/adhocMeetings/PYQC0NM0?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.comu0026onlineMeetingContext=sip:DM20R04meet1467@noammeetings.lync.com"
    },
    "service:discover": {
      "href": "https://noammeetings.resources.lync.com/platformService/discover?discoverContext=HSAUbe4hAr..."
    },
    "service:joinAdhocMeeting": {
      "href": "https://webpooldm20r04.infra.lync.com/platformservice/v1/applications/3877116191/communication/onlineMeetingInvitations?confUrl=sip:DM20R04meet1467@noammeetings.lync.com;gruu;opaque=app:conf:focus:id:PYQC0NM0u0026endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
    },
    "applications": {
      "href": "https://webpooldm20r04.infra.lync.com/ucwa/v1/applications"
    }
  },
  "rel": "service:adhocMeeting",
  "etag": "4221088333"
}

Next example is retrieving the anonymous token for this meeting.

POST https://ring2noammeetings.resources.lync.com/platformservice/v1/applications/3877116191/anonApplicationTokens?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com
Authorization: Bearer eyJ0eXAiOi...
Content-Type: application/vnd.microsoft.com.ucwa+json; charset=utf-8

{
  "meetingUrl": "https://meet.resources.lync.com/NOAMmeetings/dm20r04meet1467/PYQC0NM0",
  "allowedOrigins": "https://contoso.com/callback",
  "applicationSessionId": "test0001"
}
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.com.ucwa+json; charset=utf-8

{
  "token": "psat=eyJ0eXAiOiJKV1QiLCJh...",
  "expiryTime": "/Date(1492108195460)/",
  "_links": {
    "self": {
      "href": "https://ring2noammeetings.resources.lync.com:4443/platformservice/v1/applications/3877116191/anonApplicationTokens?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com"
    },
    "service:discover": {
      "href": "https://noammeetings.resources.lync.com/platformService/discover?anonymousMeetingJoinContext=psat%253deyJ0eXAiOiJKV1QiLCJh..."
    }
  },
  "rel": "service:anonApplicationToken"
}

Once the user gets the anonymous token, the user can join the meeting with Skype Web SDK (without Skype for Business client) as follows.
(Here I don’t explain about details, but please see “Introduction for Skype Web SDK” in my early post for Skype Web SDK programming.)

app.signInManager.signIn(
  {
    "name": "meeting01",
    "token": "Bearer psat=eyJ0eXAiOi...",
    "root": {
      "user": "https://noammeetings.resources.lync.com/platformService/discover?anonymousMeetingJoinContext=psat%253deyJ0eXAiOi..."
    },
    "cors": true
  }
).then(function () {
  ...

}, function (err) {
  ...
  
});

You can also invite the licensed user (Skype for Business user) for joining the adhoc meeting.
First your application joins adhoc meeting as follows. The uri (https://webpooldm20r04.infra.lync.com) and conversationId is retrieved (notified) by the callback endpoint, and I will explain about this callback process in the next post. (Here I don’t explain about the callback.)

POST https://webpooldm20r04.infra.lync.com/platformservice/v1/applications/3877116191/communication/onlineMeetingInvitations?confUrl=sip:DM20R04meet1467@noammeetings.lync.com;gruu;opaque=app:conf:focus:id:PYQC0NM0&endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com
Authorization: Bearer eyJ0eXAiOi...
Content-Type: application/vnd.microsoft.com.ucwa+json; charset=utf-8

{
  "operationId": "4783b19f-0e0a-4889-aca6-8d2787859f0d",
  "callbackUrl": "https://contoso.com/callback",
  "rel": "service:JoinMeetingInvitationInput"
}
HTTP/1.1 201 Created
Location: /platformservice/tgt-46c902aa67d0567bab2d9d7a16414e98/v1/applications/3877116191/communication/onlineMeetingInvitations/d56657f4-1d04-4773-bf52-4d0ae218f960?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com

Next your application invites the user to join. (Here we’re inviting BenW@MOD776816.onmicrosoft.com.)

POST https://webpooldm20r04.infra.lync.com/platformservice/tgt-46c902aa67d0567bab2d9d7a16414e98/v1/applications/3877116191/communication/participantInvitations?endpointId=sip:trustedapidemo01@mod776816.onmicrosoft.com&conversationId=c9076870-07fb-48bd-979f-49cc5498f982
Authorization: Bearer eyJ0eXAiOi...
Content-Type: application/vnd.microsoft.com.ucwa+json; charset=utf-8

{
  "operationId": "1ca3bf11-017f-418f-81d9-c80c69934b29",
  "to": "sip:BenW@MOD776816.onmicrosoft.com"
}
HTTP/1.1 201 Created

When HTTP request is sent, the licensed user (Skype for Business user) receives the following invitation in the Skype for Business client.

If the licensed user (Skype for Business user) has joined, the licensed user (staff) and the anonymous user (guest customer) can be connected through the online meeting.

Note : Currently the internal error (PlatformService.Web.PlatformServiceWebException, etc) will frequently occur, when your request is not valid. (For example, when you access the expired meeting, etc…) Sorry, but it’s difficult to know the reason of error.

SDK for Trusted Application API

If you’re .NET programmer, you can use the .NET SDK for calling Trusted Application API.
You just install the following NuGet package in your project. (Note that .NET 4.6.2 is needed, and select [include prerelease] like the following screenshot.)

Microsoft.SkypeforBusiness.TrustedApplicationAPI.SDK
Microsoft.SkypeforBusiness.TrustedApplicationAPI.ResourceContact

The following is the C# programming example of the previous HTTP flow (including authentication, initialization, ad-hoc meeting creation, and getting anonymous token).
Sorry, but it’s classic Win Form application … (In most cases, the real application will be hosted on Web.)

...
using Microsoft.SfB.PlatformService.SDK.Common;
using Microsoft.SfB.PlatformService.SDK.ClientModel;

...

public ClientPlatformSettings platsettings = null;
public ApplicationEndpoint appendpoint = null;
public string joinUrl = null;

private async void Initialize()
{
  platsettings = new ClientPlatformSettings(
    "kEQ2B1rCsf...", // secret (key)
    Guid.Parse("d4daaf71-5f06-4f70-bf4b-418a97f34741")); // application id
  var clplatform = new ClientPlatform(
    platsettings,
    new MyLogger());
  var endpointsettings = new ApplicationEndpointSettings(
    new SipUri("sip:trustedapidemo01@mod776816.onmicrosoft.com")); // sip uri
  appendpoint = new ApplicationEndpoint(
    clplatform,
    endpointsettings,
    null);
  await appendpoint.InitializeAsync().
    ConfigureAwait(false);
  await appendpoint.InitializeApplicationAsync().
    ConfigureAwait(false);
  MessageBox.Show("done");
}

private async void CreateAdhocMeeting()
{
  var createarg = new AdhocMeetingCreationInput("meeting01");
  var adhocmeetingResources =
    await appendpoint.Application.CreateAdhocMeetingAsync(createarg)
    .ConfigureAwait(false);
  joinUrl = adhocmeetingResources.JoinUrl;
  MessageBox.Show("done");
}

private async void GetAnonymousToken()
{
  var tokenResources =
    await appendpoint.Application.GetAnonApplicationTokenForMeetingAsync(
      joinUrl,
      @"https://contoso.com/callback",
      "test0001").ConfigureAwait(false);
  MessageBox.Show("done");
}

private async void InviteSkypeUser() // Join meeting -> Invite user
{
  // Here I don't describe the code, because it needs callback ...
  // I will explain about callback (webhook) in the next post.
}

...

public class MyLogger : IPlatformServiceLogger
{
  public bool HttpRequestResponseNeedsToBeLogged { get; set; }

  public void Information(string message)
  {
    MessageBox.Show($"[INFO]{message}");
  }

  public void Information(string fmt, params object[] vars)
  {
    MessageBox.Show($"[INFO]{string.Format(fmt, vars)}");
  }

  public void Information(Exception exception, string fmt, params object[] vars)
  {
    MessageBox.Show($"[INFO]{string.Format(fmt, vars)}");
  }

  public void Warning(string message)
  {
    MessageBox.Show($"[WARN]{message}");
  }

  public void Warning(string fmt, params object[] vars)
  {
    MessageBox.Show($"[WARN]{string.Format(fmt, vars)}");
  }

  public void Warning(Exception exception, string fmt, params object[] vars)
  {
    MessageBox.Show($"[WARN]{string.Format(fmt, vars)}");
  }

  public void Error(string message)
  {
    MessageBox.Show($"[ERR]{message}");
  }

  public void Error(string fmt, params object[] vars)
  {
    MessageBox.Show($"[ERR]{string.Format(fmt, vars)}");
  }

  public void Error(Exception exception, string fmt, params object[] vars)
  {
    MessageBox.Show($"[ERR]{string.Format(fmt, vars)}");
  }
}

 

Reference : early posts (all Japanese) for “Skype for Business” development platform

Categories: Uncategorized

Tagged as: ,

9 replies »

  1. Hi Tsuyoshi,
    I just follow your steps to do gets the anonymous token, the first time i can get the token when post the “service:anonApplicationTokens” endpoint. after that, it always return 307 status when i run it again, details as below. any suggestions for this issue?
    “statusCode”: 307,
    “headers”: {
    “cache-control”: “no-cache”,
    “pragma”: “no-cache”,
    “expires”: “-1”,
    “location”: “https://webpoolsgxxxxx.infra.lync.com/platformservice/v1/applications/3213816010/anonApplicationTokens?endpointId=sip%3asample%40xxxxx.onmicrosoft.com&redirect=1”,
    “x-ms-platformservicebuild”: “7.0.1569.0”,
    “x-ms-clientdiagnostics”: “T3B…”,
    “x-ms-server-fqdn”: “HK20R04FES14.infra.lync.com”,
    “x-ms-correlation-id”: “4e83ac6f-d8fb-4240-b9dd-8485952de666”,
    “x-ms-client-request-id”: “b42e4fee-f95e-4fae-8482-399a5d72553e”,
    “strict-transport-security”: “max-age=31536000; includeSubDomains”,
    “date”: “Fri, 28 Apr 2017 02:33:37 GMT”,
    “connection”: “close”,
    “content-length”: “0”
    },
    “request”: {
    “uri”: {
    “protocol”: “https:”,
    “slashes”: true,
    “auth”: null,
    “host”: “ring2apacmeetings.resources.lync.com”,
    “port”: 443,
    “hostname”: “ring2apacmeetings.resources.lync.com”,
    “hash”: null,
    “search”: “?endpointId=sip:sample@xxxxx.onmicrosoft.com”,
    “query”: “endpointId=sip:sample@xxxxx.onmicrosoft.com”,
    “pathname”: “/platformservice/v1/applications/3213816010/anonApplicationTokens”,
    “path”: “/platformservice/v1/applications/3213816010/anonApplicationTokens?endpointId=sip:sample@xxxxx.onmicrosoft.com”,
    “href”: “https://ring2apacmeetings.resources.lync.com/platformservice/v1/applications/3213816010/anonApplicationTokens?endpointId=sip:sample@xxxxx.onmicrosoft.com”
    },
    “method”: “POST”,
    “headers”: {
    “Authorization”: “Bearer eyJ…”,
    “accept”: “application/json”,
    “content-type”: “application/json”,
    “content-length”: 112
    }
    }

    Like

  2. Hi Matsuzaki,
    I just follow this article to get anonymous application token, no problem there when the first time run my application and i can get the anonymous token. but when i run it again after a period of time, it always return 307 status when call “service:anonApplicationTokens” endpoint used the application token and the same code, and attached the response details as below. will appreciated it if you can give me some suggestions, and as you said, once we gets the anonymous token, we can join the meeting with Skype Web SDK, and also want to know where to get the user property value(“https://noammeetings.resources.lync.com/platformService/discover?anonymousMeetingJoinContext=psat%253deyJ0eXAiOi…”), just hard code it as your sample?

    {
    “statusCode”: 307,
    “headers”: {
    “cache-control”: “no-cache”,
    “pragma”: “no-cache”,
    “expires”: “-1”,
    “location”: “https://webpoolsgxxxxx.infra.lync.com/platformservice/v1/applications/3213816010/anonApplicationTokens?endpointId=sip%3asample%40xxxxx.onmicrosoft.com&redirect=1”,
    “x-ms-platformservicebuild”: “7.0.1569.0”,
    “x-ms-clientdiagnostics”: “T3B…”,
    “x-ms-server-fqdn”: “HK20R04FES14.infra.lync.com”,
    “x-ms-correlation-id”: “4e83ac6f-d8fb-4240-b9dd-8485952de666”,
    “x-ms-client-request-id”: “b42e4fee-f95e-4fae-8482-399a5d72553e”,
    “strict-transport-security”: “max-age=31536000; includeSubDomains”,
    “date”: “Fri, 28 Apr 2017 02:33:37 GMT”,
    “connection”: “close”,
    “content-length”: “0”
    },
    “request”: {
    “uri”: {
    “protocol”: “https:”,
    “slashes”: true,
    “auth”: null,
    “host”: “ring2apacmeetings.resources.lync.com”,
    “port”: 443,
    “hostname”: “ring2apacmeetings.resources.lync.com”,
    “hash”: null,
    “search”: “?endpointId=sip:sample@xxxxx.onmicrosoft.com”,
    “query”: “endpointId=sip:sample@xxxxx.onmicrosoft.com”,
    “pathname”: “/platformservice/v1/applications/3213816010/anonApplicationTokens”,
    “path”: “/platformservice/v1/applications/3213816010/anonApplicationTokens?endpointId=sip:sample@xxxxx.onmicrosoft.com”,
    “href”: “https://ring2apacmeetings.resources.lync.com/platformservice/v1/applications/3213816010/anonApplicationTokens?endpointId=sip:sample@xxxxx.onmicrosoft.com”
    },
    “method”: “POST”,
    “headers”: {
    “Authorization”: “Bearer eyJ…”,
    “accept”: “application/json”,
    “content-type”: “application/json”,
    “content-length”: 112
    }
    }
    }

    Like

  3. Hi, Marquis-san and Humaruis-san
    Sorry for late response, because of the long holiday (national holiday) in Japan.
    I tried using Fiddler and I cannot figure out this response. But the status 307 means temporary redirection, then can you please call again with the new location uri like https://xxxxx.infra.lync.com/platformservice/v1/applications/xxxxx/anonApplicationTokens?endpointId=sip%3axxxxx%40xxxxx.onmicrosoft.com&redirect=1 (with “redirect=1”) ?

    Like

    • Hi Matsuzaki,
      Thank you for the information, i used a temporary solution solved it by hard code the location “https://noammeetings.resources.lync.com” instead of “https://webpoolsgxxxxx.infra.lync.com”, and will try it again adopt your suggestions. There are some other problem about the trusted application api, will appreciated it if you can give me some suggestions, thanks in advance.
      1. As we know the default expiry value is one hour, want to know how to refresh the token again when it’s expire?
      2. About join anonymous meeting with Skype Web SDK, how to invite the licensed user join the adhoc meeting? refer to your blog about “participantInvitations” part and also checked the source code about WebClient Samples(https://sdksamplesucap.azurewebsites.net), seems like it’s triggered on webhook event(callback) in backend? which means we can only do it in callback process rather than UI side?
      3. For trusted application api, if we start audio in a meeting with licensed user, whether we can get the speech information?

      Like

      • Sorry for late response.
        >>1. As we know the default expiry value is one hour, want to know how to refresh the token again when it’s expire?
        You can get the access token with the same POST request against https://login.microsoftonline.com/mod776816.onmicrosoft.com/oauth2/token, because this scenario doesn’t show the login UI. (No need to use “refresh token”.)
        >> 2. About join anonymous meeting with Skype Web SDK, how to invite the licensed user join the adhoc meeting?
        For example, you can create your own web app with Sky Web SDK, and you can invite into this page with e-mail or etc.
        If possible, please refer the New Virtual Health Template (below) because it’s very useful example. This sample (New Virtual Health Template) uses the same approaches: The patient receives the e-mail with “Join Meeting” link, and the patient can join with this web page without authentication (with annon token).
        https://blogs.office.com/2017/02/16/new-virtual-health-templates-extend-skype-for-business-as-platform-for-developers/

        Like

  4. Thank you for this great tutorial!

    Everything works, except, when I try this with my Office 365 developers subscription, contacting
    GET https://api.skypeforbusiness.com/platformservice/discover with correct app context token results into:
    403 – Forbidden – Invalid Tenant or no region found for this tenant – error

    Did anyone experienced same error and found how to fix it?

    Like

  5. Hi Tsuyoshi Matsuzaki,
    While using the “add-participant resource” a invitation is sent to the licensed user ( a Skype for business client) but the notification message is cryptic.. like my enpoint Id followed by a random number and my domain name like for example :
    “testchat@122227442554633322214@domainname.com”,

    Like

  6. Great beat ! I wish to apprentice while you amend your website, how can i subscribe for a blog site? The account aided me a acceptable deal. I had been a little bit acquainted of this your broadcast provided bright clear concept|

    Like

Leave a Reply