Retrieve E-Mails for the user accessing this 'Web App' by communicating with the Microsoft authentication
service and the Office 365 REST APIs (w/o using Connected Services libraries).
The first step is to create a new project in Azure of the Office 365 hosted domain. A good reference
on how to do this is found here.
The next steps describe how to authorize with Microsoft Online:
https://login.windows.net/common/oauth2/authorize?response_type=code&client_id=ae0020cb...&redirect_uri=https://consulity.de/content/Office365APIs.aspx&resource=https:%2f%2foutlook.office365.com%2f&state=5asdfadsffd60b-8457-4536-b20f-fcb658d1asdfasdfasd9458
Microsoft provides two different versions of projects: Azure Active Directory (AAD) projects and Microsoft Apps (v2.0 endpoint).
The reference used to build the initial project follows AAD, below you can find the login buttons for Version 2 endpoint authentication.
Please also confer the sources and links given at the end of the page for additional information concerning v2.0 apps.
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=code&client_id=b99ac069...&redirect_uri= https://consulity.de/content/Office365APIs.aspx&scope=openid+offline_access+profile+https:%2f%2foutlook.office.com%2fmail.read&state=abc57446-73ed-4508-9e05-f3d6faa4939e&prompt=login
Note: The state parameter (arbitrary string that is hard to guess) should be generated and added to the link server side.
Please also note that in case the permission was not granted, an error is returned that has to be handeled (not implemented here).
With the access code retrieved after the successful login, it is possible to generate the Access Token
and the Refresh Token.
In our example the retrieval of the access token and the refresh token is done with
an xmlHttp request to the following URL (server side) passing the access code retrieved from the authorization step.
Note: The real link is built server side and does not need a distinction between localhost and live version.
The base token URL is:
POST https://login.windows.net/common/oauth2/token
The body is form encoded:
grant_type=authorization_code&code={code from the authorize request}&redirect_uri={reply url for your application}&client_id={your application’s client id in AAD}&client_secret={your application’s client secret}
Now we want to retrieve the last two e-mails of the user accessing this service.
In order to do that, we pass the Bearer token to the Outlook/Office 365 API.
As an access token is only valid for a defined period of time, the access token can be refreshed.
If the server persists the refresh token, it can receive new access tokens anytime unlesse the user
revokes the given trus in the connected apps of his account profile.
https://login.microsoftonline.com/common/oauth2/token?grant_type=refresh_token&refresh_token=AAABAAAAiL9...
&client_id=ae0020cb-2e0d-4e9e-ab8e-bceb50db5d30&client_secret=%2bPR...
Please note: Some APIs, e.g. SharePoint Online, are not yet (2016-07-04) supported in V2 projects.
Instead of using HTTP-Requests, it is also possible to use a Connected Service reference
to Office 365 via Visual Studio. In this case .NET libraries can be used to perform the steps
shown above.
Please note: the Connected Service libraries are ideal to use with Microsoft APS.NET MVC pattern due
async calls, e.g. the browser window asks for user credentials and the process continues after
successful submission asynchronously. Async Procedures can be achieved with .NET 4.5 but MVC seems to
be the better pattern.
Imports System.Collections.Generic
Imports System.IO
Imports System.Net
Imports System.Web.Script.Serialization
Partial Class _Default
Inherits consulity.Web.Page
Private Const CLIENT_ID
As String = "...removed..."
Private Const CLIENT_ID_V2
As String = "...removed..."
Private Const CLIENT_SECRET
As String = "...removed..."
Private Const CLIENT_SECRET_V2
As String = "...removed..."
' if offline_access is not given, no refresh_token will be responded
Private Const SCOPE_V2
As String = "openid+profile+https:%2f%2foutlook.office.com%2fmail.read"
' Private Const SCOPE_V2 As String = "openid+offline_access+profile+https%3A%2F%2Foutlook.office.com%2Fmail.read" ' colon not encoded?
Private Sub
_Default_Load(sender As Object, e As
EventArgs) Handles Me.Load
Dim strAccessCode As
String = Request.Params("code")
If strAccessCode <> ""
Then
Me.divCode.InnerHtml = strAccessCode
End If
End Sub
Private Function GetMailsV2(ByVal
strToken As String) As
String
Dim URL As
String = "https://outlook.office.com/api/v2.0/me/mailfolders/inbox/messages?$top=2"
Dim request As
WebRequest = WebRequest.Create(URL)
request.Method = "GET"
request.Headers.Add("client-request-id", HttpContext.Current.Server.UrlEncode(CLIENT_ID_V2))
request.Headers.Add("authorization", "Bearer "
& HttpContext.Current.Server.UrlEncode(strToken))
Dim dataStream As
Stream
Dim response As
WebResponse = request.GetResponse()
dataStream = response.GetResponseStream()
Dim reader As
New StreamReader(dataStream)
Dim responseFromServer As
String = reader.ReadToEnd()
reader.Close()
dataStream.Close()
response.Close()
Return responseFromServer
End Function
Private Function GetMailsV1(ByVal
strToken As String) As
String
Dim URL As
String = "https://outlook.office.com/api/v1.0/me/folders/inbox/messages?$top=2"
Dim request As
WebRequest = WebRequest.Create(URL)
request.Method = "GET"
request.Headers.Add("client-request-id", HttpContext.Current.Server.UrlEncode(CLIENT_ID))
request.Headers.Add("authorization", "Bearer "
& HttpContext.Current.Server.UrlEncode(strToken))
Dim dataStream As
Stream
Dim response As
WebResponse = request.GetResponse()
dataStream = response.GetResponseStream()
Dim reader As
New StreamReader(dataStream)
Dim responseFromServer As
String = reader.ReadToEnd()
reader.Close()
dataStream.Close()
response.Close()
Return responseFromServer
End Function
'https://msdn.microsoft.com/en-us/library/debx8sh9(v=vs.110).aspx
Private Function GetPOSTResult(ByVal
strURL As String, ByVal
strPostData As String) As
String
Dim request As
WebRequest = WebRequest.Create(strURL)
' Set the Method property of the request to POST.
request.Method = "POST"
' Create POST data and convert it to a byte array.
Dim postData As
String = strPostData
Dim byteArray As
Byte() = Encoding.UTF8.GetBytes(postData)
' Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded"
' Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length
' Get the request stream.
Dim dataStream As
Stream = request.GetRequestStream()
' Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length)
' Close the Stream object.
dataStream.Close()
' Get the response.
Dim response As
WebResponse = request.GetResponse()
' Display the status.
Console.WriteLine(CType(response,
HttpWebResponse).StatusDescription)
' Get the stream containing content returned by the server.
dataStream = response.GetResponseStream()
' Open the stream using a StreamReader for easy access.
Dim reader As
New StreamReader(dataStream)
' Read the content.
Dim responseFromServer As
String = reader.ReadToEnd()
' Display the content.
Console.WriteLine(responseFromServer)
' Clean up the streams.
reader.Close()
dataStream.Close()
response.Close()
Return responseFromServer
End Function
Private Sub
btnGetTokensV1_Click(sender As Object, e As
EventArgs) Handles btnGetTokensV1.Click
Dim strAccessCode As
String = Request.Params("code")
Const BASE_URI As
String = "https://login.windows.net/common/oauth2/token"
Const GRANT_TYPE As
String = "grant_type=authorization_code"
Dim url As
String = HttpContext.Current.Request.Url.AbsoluteUri
Dim url_plain = url.Substring(0, url.IndexOf("?"))
Dim strCode As
String = "&code=" & HttpContext.Current.Server.UrlEncode(strAccessCode)
Dim strRedirect As
String = "&redirect_uri=" & HttpContext.Current.Server.UrlEncode(url_plain)
Dim strScope As
String = "&scope=openid+offline_access+profile+https%3A%2F%2Foutlook.office.com%2Fmail.read"
Dim strClientId As
String = "&client_id=" & HttpContext.Current.Server.UrlEncode(CLIENT_ID)
Dim strClientSecret As
String = "&client_secret=" & HttpContext.Current.Server.UrlEncode(CLIENT_SECRET)
Dim strPostData As
String
strPostData = GRANT_TYPE & strCode & strRedirect & strScope & strClientId & strClientSecret
Dim strResult As
String = GetPOSTResult(BASE_URI, strPostData)
Me.divTokens.InnerHtml = Left(strResult, 200)
' parse the result and retrieve the bearer access token
Dim ss As
New JavaScriptSerializer
Dim co As
Dictionary(Of String,
Object) = ss.DeserializeObject(strResult)
Dim strAccessToken As
String = co("access_token")
Dim strRefreshToken As
String = co("refresh_token")
' store the access token in session
Session("AT") = strAccessToken
' store the access token in session - (...persist in DB)
Session("RT") = strRefreshToken
End Sub
Private Sub
btnGetTokensV2_Click(sender As Object, e As
EventArgs) Handles btnGetTokensV2.Click
Dim strAccessCode As
String = Request.Params("code")
Const BASE_URI As
String = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
Const GRANT_TYPE As
String = "grant_type=authorization_code"
Dim url As
String = HttpContext.Current.Request.Url.AbsoluteUri
Dim url_plain = url.Substring(0, url.IndexOf("?"))
Dim strCode As
String = "&code=" & HttpContext.Current.Server.UrlEncode(strAccessCode)
Dim strRedirect As
String = "&redirect_uri=" & HttpContext.Current.Server.UrlEncode(url_plain)
Dim strScope As
String = "&scope=" & SCOPE_V2
Dim strClientId As
String = "&client_id=" & HttpContext.Current.Server.UrlEncode(CLIENT_ID_V2)
Dim strClientSecret As
String = "&client_secret=" & HttpContext.Current.Server.UrlEncode(CLIENT_SECRET_V2)
Dim strPostData As
String
strPostData = GRANT_TYPE & strCode & strRedirect & strScope & strClientId & strClientSecret
Dim strResult As
String = GetPOSTResult(BASE_URI, strPostData)
Me.divTokens.InnerHtml = Left(strResult, 200)
' parse the result and retrieve the bearer access token
'Dim strAccessToken As String = JObject.Parse(strResult)("access_token")
'Dim strRefreshToken As String = JObject.Parse(strResult)("refresh_token")
Dim ss As
New JavaScriptSerializer
Dim co As
Dictionary(Of String,
Object) = ss.DeserializeObject(strResult)
Dim strAccessToken As
String = co("access_token")
Dim strRefreshToken As
String = co("refresh_token")
' store the access token in session
Session("AT") = strAccessToken
' store the access token in session - (...persist in DB)
Session("RT") = strRefreshToken
End Sub
Private Sub
btnGetMailsV1_Click(sender As Object, e As
EventArgs) Handles btnGetMailsV1.Click
' call the mail API
Me.divRMails.InnerHtml = Strings.Replace(HttpContext.Current.Server.HtmlEncode(GetMailsV1(Session("AT"))),
",", ",<br>")
End Sub
Private Sub
btnGetMailsV2_Click(sender As Object, e As
EventArgs) Handles btnGetMailsV2.Click
' call the mail API
Me.divRMails.InnerHtml = Strings.Replace(HttpContext.Current.Server.HtmlEncode(GetMailsV2(Session("AT"))),
",", ",<br>")
End Sub
Private Sub
btnGetR2AV1_Click(sender As Object, e As
EventArgs) Handles btnGetR2AV1.Click
' refresh access token
Dim strAccessCode As
String = Request.Params("code")
Const BASE_URI As
String = "https://login.microsoftonline.com/common/oauth2/token"
Const GRANT_TYPE As
String = "grant_type=refresh_token"
Dim url As
String = HttpContext.Current.Request.Url.AbsoluteUri
Dim url_plain = url.Substring(0, url.IndexOf("?"))
Dim strCode As
String = "&refresh_token=" & Session("RT")
Dim strClientId As
String = "&client_id=" & HttpContext.Current.Server.UrlEncode(CLIENT_ID)
Dim strClientSecret As
String = "&client_secret=" & HttpContext.Current.Server.UrlEncode(CLIENT_SECRET)
Dim strPostData As
String
strPostData = GRANT_TYPE & strCode & strClientId & strClientSecret
Dim strResult As
String = GetPOSTResult(BASE_URI, strPostData)
Me.divRefresh.InnerHtml = Left(strResult, 200)
' parse the result and retrieve the bearer access token
Dim ss As
New JavaScriptSerializer
Dim co As
Dictionary(Of String,
Object) = ss.DeserializeObject(strResult)
Dim strAccessToken As
String = co("access_token")
Dim strRefreshToken As
String = co("refresh_token")
' store the access token in session
Session("AT") = strAccessToken
' store the access token in session - (...persist in DB)
Session("RT") = strRefreshToken
End Sub
Private Sub
btnGetR2AV2_Click(sender As Object, e As
EventArgs) Handles btnGetR2AV2.Click
' refresh access token
Const BASE_URI As
String = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
Const GRANT_TYPE As
String = "&grant_type=refresh_token"
Dim url As
String = HttpContext.Current.Request.Url.AbsoluteUri
Dim url_plain = url.Substring(0, url.IndexOf("?"))
Dim strClientId As
String = "client_id=" & HttpContext.Current.Server.UrlEncode(CLIENT_ID_V2)
Dim strCode As
String = "&refresh_token=" & HttpContext.Current.Server.UrlEncode(Session("RT"))
Dim strScope As
String = "&scope=" & SCOPE_V2
Dim strRedirect As
String = "&redirect_uri=" & HttpContext.Current.Server.UrlEncode(url_plain)
Dim strClientSecret As
String = "&client_secret=" & HttpContext.Current.Server.UrlEncode(CLIENT_SECRET_V2)
Dim strPostData As
String
strPostData = strClientId & strScope & strCode & strRedirect & GRANT_TYPE & strClientSecret
Dim strResult As
String = GetPOSTResult(BASE_URI, strPostData)
Me.divRefresh.InnerHtml = Left(strResult, 200)
' parse the result and retrieve the bearer access token
Dim ss As
New JavaScriptSerializer
Dim co As
Dictionary(Of String,
Object) = ss.DeserializeObject(strResult)
Dim strAccessToken As
String = co("access_token")
' the response will not deliver a refresh token for Microsoft Accounts, only for Office 365 accounts
' the "refresh_token" is deliverd
Try
Dim strRefreshToken As
String = co("refresh_token")
' store the access token in session - (...persist in DB)
Session("RT") = strRefreshToken
Catch ex As
Exception
Me.divRefresh.InnerHtml &= "<hr>" & ex.Message
End Try
' store the access token in session
Session("AT") = strAccessToken
End Sub
End Class