Commit 081ec987 authored by Jake Oandasan's avatar Jake Oandasan

Office 365 API demo code

parent 71628e16
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_KEY=base64:32jrq6sfe9SYW3XQOu5WvM9/Tk5sQs4Zy3sx66X+uhc=
APP_DEBUG=true
APP_URL=http://localhost
......@@ -16,7 +16,7 @@ DB_PASSWORD=
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=cookie
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
......@@ -42,3 +42,11 @@ PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
OAUTH_APP_ID=6befc560-24c8-49da-a234-3a01606590e9
OAUTH_APP_PASSWORD=MZM.w?27eui=NaWWRye6i?Bt4C:NftPV
OAUTH_REDIRECT_URI=http://localhost:8000/callback
OAUTH_SCOPES='openid profile offline_access user.read calendars.read'
OAUTH_AUTHORITY=https://login.microsoftonline.com/common
OAUTH_AUTHORIZE_ENDPOINT=/oauth2/v2.0/authorize
OAUTH_TOKEN_ENDPOINT=/oauth2/v2.0/token
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Microsoft\Graph\Graph;
use Microsoft\Graph\Model;
use App\TokenStore\TokenCache;
class CalendarController extends Controller
{
public function calendar()
{
$viewData = $this->loadViewData();
// Get the access token from the cache
$tokenCache = new TokenCache();
$accessToken = $tokenCache->getAccessToken();
// Create a Graph client
$graph = new Graph();
$graph->setAccessToken($accessToken);
$queryParams = array(
'$select' => 'subject,organizer,start,end',
'$orderby' => 'createdDateTime DESC'
);
// Append query parameters to the '/me/events' url
$getEventsUrl = '/me/events?'.http_build_query($queryParams);
$events = $graph->createRequest('GET', $getEventsUrl)
->setReturnType(Model\Event::class)
->execute();
$viewData['events'] = $events;
return view('calendar', $viewData);
}
}
\ No newline at end of file
......@@ -2,12 +2,32 @@
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function loadViewData()
{
$viewData = [];
// Check for flash errors
if (session('error')) {
$viewData['error'] = session('error');
$viewData['errorDetail'] = session('errorDetail');
}
// Check for logged on user
if (session('userName'))
{
$viewData['userName'] = session('userName');
$viewData['userEmail'] = session('userEmail');
}
return $viewData;
}
}
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function welcome()
{
$viewData = $this->loadViewData();
return view('home', $viewData);
}
}
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Microsoft\Graph\Graph;
use Microsoft\Graph\Model;
use App\TokenStore\TokenCache;
class MicrosoftGraphController extends Controller
{
public function signin()
{
// Initialize the OAuth client
$oauthClient = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => env('OAUTH_APP_ID'),
'clientSecret' => env('OAUTH_APP_PASSWORD'),
'redirectUri' => env('OAUTH_REDIRECT_URI'),
'urlAuthorize' => env('OAUTH_AUTHORITY').env('OAUTH_AUTHORIZE_ENDPOINT'),
'urlAccessToken' => env('OAUTH_AUTHORITY').env('OAUTH_TOKEN_ENDPOINT'),
'urlResourceOwnerDetails' => '',
'scopes' => env('OAUTH_SCOPES')
]);
$authUrl = $oauthClient->getAuthorizationUrl();
// Save client state so we can validate in callback
session(['oauthState' => $oauthClient->getState()]);
// Redirect to AAD signin page
return redirect()->away($authUrl);
}
public function callback(Request $request)
{
// Validate state
$expectedState = session('oauthState');
$request->session()->forget('oauthState');
$providedState = $request->query('state');
if (!isset($expectedState)) {
// If there is no expected state in the session,
// do nothing and redirect to the home page.
return redirect('/');
}
if (!isset($providedState) || $expectedState != $providedState) {
return redirect('/')
->with('error', 'Invalid auth state')
->with('errorDetail', 'The provided auth state did not match the expected value');
}
// Authorization code should be in the "code" query param
$authCode = $request->query('code');
if (isset($authCode)) {
// Initialize the OAuth client
$oauthClient = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => env('OAUTH_APP_ID'),
'clientSecret' => env('OAUTH_APP_PASSWORD'),
'redirectUri' => env('OAUTH_REDIRECT_URI'),
'urlAuthorize' => env('OAUTH_AUTHORITY').env('OAUTH_AUTHORIZE_ENDPOINT'),
'urlAccessToken' => env('OAUTH_AUTHORITY').env('OAUTH_TOKEN_ENDPOINT'),
'urlResourceOwnerDetails' => '',
'scopes' => env('OAUTH_SCOPES')
]);
try {
// Make the token request
$accessToken = $oauthClient->getAccessToken('authorization_code', [
'code' => $authCode
]);
$graph = new Graph();
$graph->setAccessToken($accessToken->getToken());
$user = $graph->createRequest('GET', '/me')
->setReturnType(Model\User::class)
->execute();
$tokenCache = new TokenCache();
$tokenCache->storeTokens($accessToken, $user);
return redirect('/');
}
catch (League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
return redirect('/')
->with('error', 'Error requesting access token')
->with('errorDetail', $e->getMessage());
}
}
return redirect('/')
->with('error', $request->query('error'))
->with('errorDetail', $request->query('error_description'));
}
public function signout()
{
$tokenCache = new TokenCache();
$tokenCache->clearTokens();
return redirect('/');
}
public function requestQuery($uri)
{
// Get the access token from the cache
$tokenCache = new TokenCache();
$accessToken = $tokenCache->getAccessToken();
// Check if there's an access token
if ($accessToken == null)
{
return redirect('/')
->with('error', 'No access token available.')
->with('errorDetail', 'If you are not signed in, please sign in.');
}
// Create a Graph client
$graph = new Graph();
$graph->setAccessToken($accessToken);
$getEventsUrl = $uri;
return $graph->createRequest('GET', $getEventsUrl)
->setReturnType(Model\Event::class)
->execute();
}
public function getMyInfo()
{
return $this->requestQuery('/me');
}
public function getAllUsers()
{
return $this->requestQuery('/users');
}
public function getMyTeams()
{
return $this->requestQuery('/me/joinedTeams');
}
public function getAllGroups()
{
return $this->requestQuery('/groups');
}
public function getTeamMembers($groupId)
{
return $this->requestQuery('/groups/' . $groupId . '/members');
}
public function getTeamInfo($groupId)
{
return $this->requestQuery('/teams/' . $groupId);
}
public function getMyLicense()
{
return $this->requestQuery('/me/licenseDetails');
}
public function getUserLicense($userId)
{
return $this->requestQuery('/users/' . $userId . '/licenseDetails');
}
}
<?php
namespace App\TokenStore;
class TokenCache {
public function storeTokens($accessToken, $user) {
session([
'accessToken' => $accessToken->getToken(),
'refreshToken' => $accessToken->getRefreshToken(),
'tokenExpires' => $accessToken->getExpires(),
'userName' => $user->getDisplayName(),
'userEmail' => null !== $user->getMail() ? $user->getMail() : $user->getUserPrincipalName()
]);
}
public function updateTokens($accessToken) {
session([
'accessToken' => $accessToken->getToken(),
'refreshToken' => $accessToken->getRefreshToken(),
'tokenExpires' => $accessToken->getExpires()
]);
}
public function clearTokens() {
session()->forget('accessToken');
session()->forget('refreshToken');
session()->forget('tokenExpires');
session()->forget('userName');
session()->forget('userEmail');
}
public function getAccessToken() {
// Check if tokens exist
if (empty(session('accessToken')) ||
empty(session('refreshToken')) ||
empty(session('tokenExpires'))) {
return '';
}
// Check if token is expired
//Get current time + 5 minutes (to allow for time differences)
$now = time() + 300;
if (session('tokenExpires') <= $now) {
// Token is expired (or very close to it)
// so let's refresh
// Initialize the OAuth client
$oauthClient = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => env('OAUTH_APP_ID'),
'clientSecret' => env('OAUTH_APP_PASSWORD'),
'redirectUri' => env('OAUTH_REDIRECT_URI'),
'urlAuthorize' => env('OAUTH_AUTHORITY').env('OAUTH_AUTHORIZE_ENDPOINT'),
'urlAccessToken' => env('OAUTH_AUTHORITY').env('OAUTH_TOKEN_ENDPOINT'),
'urlResourceOwnerDetails' => '',
'scopes' => env('OAUTH_SCOPES')
]);
try {
$newToken = $oauthClient->getAccessToken('refresh_token', [
'refresh_token' => session('refreshToken')
]);
// Store the new values
$this->updateTokens($newToken);
return $newToken->getToken();
}
catch (League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
return '';
}
}
// Token is still valid, just return it
return session('accessToken');
}
}
\ No newline at end of file
......@@ -10,8 +10,10 @@
"require": {
"php": "^7.2",
"fideloper/proxy": "^4.0",
"laravel/framework": "^6.2",
"laravel/tinker": "^2.0"
"laravel/framework": "^6.0",
"laravel/tinker": "^1.0",
"league/oauth2-client": "dev-master",
"microsoft/microsoft-graph": "^1.10"
},
"require-dev": {
"facade/ignition": "^1.4",
......
This diff is collapsed.
body {
padding-top: 4.5rem;
}
.alert-pre {
word-wrap: break-word;
word-break: break-all;
white-space: pre-wrap;
}
\ No newline at end of file
@extends('layout')
@section('content')
<h1>Calendar</h1>
<table class="table">
<thead>
<tr>
<th scope="col">Organizer</th>
<th scope="col">Subject</th>
<th scope="col">Start</th>
<th scope="col">End</th>
</tr>
</thead>
<tbody>
@isset($events)
@foreach($events as $event)
<tr>
<td>{{ $event->getOrganizer()->getEmailAddress()->getName() }}</td>
<td>{{ $event->getSubject() }}</td>
<td>{{ \Carbon\Carbon::parse($event->getStart()->getDateTime())->format('n/j/y g:i A') }}</td>
<td>{{ \Carbon\Carbon::parse($event->getEnd()->getDateTime())->format('n/j/y g:i A') }}</td>
</tr>
@endforeach
@endif
</tbody>
</table>
@endsection
\ No newline at end of file
@extends('layout')
@section('content')
<div class="jumbotron">
<h1>PHP Graph Tutorial</h1>
<p class="lead">This sample app shows how to use the Microsoft Graph API to access Office 365 data from PHP</p>
@if(isset($userName))
<h4>Welcome {{ $userName }}!</h4>
<p>Use the navigation bar at the top of the page to get started.</p>
@else
<a href="/signin" class="btn btn-primary btn-large">Click here to sign in</a>
@endif
</div>
@endsection
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<title>PHP Graph Tutorial</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css"
integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css"
integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
<link rel="stylesheet" href="{{ asset('/css/app.css') }}">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"
integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div class="container">
<a href="/" class="navbar-brand">PHP Graph Tutorial</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse"
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item" style="font-size: 12px;">
<a href="/" class="nav-link {{$_SERVER['REQUEST_URI'] == '/' ? ' active' : ''}}">Home</a>
</li>
@if(isset($userName))
<li class="nav-item" style="font-size: 12px;" data-turbolinks="false">
<a href="/calendar" class="nav-link{{$_SERVER['REQUEST_URI'] == '/calendar' ? ' active' : ''}}">Calendar</a>
</li>
<li class="nav-item" style="font-size: 12px;" data-turbolinks="false">
<a href="/me" class="nav-link{{$_SERVER['REQUEST_URI'] == '/me' ? ' active' : ''}}">My Info</a>
</li>
<li class="nav-item" style="font-size: 12px;" data-turbolinks="false">
<a href="/users" class="nav-link{{$_SERVER['REQUEST_URI'] == '/users' ? ' active' : ''}}">All Users</a>
</li>
<li class="nav-item" style="font-size: 12px;" data-turbolinks="false">
<a href="/joinedTeams" class="nav-link{{$_SERVER['REQUEST_URI'] == '/joinedTeams' ? ' active' : ''}}">Joined Teams</a>
</li>
<li class="nav-item" style="font-size: 12px;" data-turbolinks="false">
<a href="/groups" class="nav-link{{$_SERVER['REQUEST_URI'] == '/groups' ? ' active' : ''}}">All Groups</a>
</li>
<li class="nav-item" style="font-size: 12px;" data-turbolinks="false">
<a href="/membersOfTeam/d1c164c6-db90-4c5b-b668-3ea57cb973cd" class="nav-link{{$_SERVER['REQUEST_URI'] == '/membersOfTeam/d1c164c6-db90-4c5b-b668-3ea57cb973cd' ? ' active' : ''}}">Team Members</a>
</li>
<li class="nav-item" style="font-size: 12px;" data-turbolinks="false">
<a href="/teamInfo/d1c164c6-db90-4c5b-b668-3ea57cb973cd" class="nav-link{{$_SERVER['REQUEST_URI'] == '/teamInfo/d1c164c6-db90-4c5b-b668-3ea57cb973cd' ? ' active' : ''}}">Team Info</a>
</li>
<li class="nav-item" style="font-size: 12px;" data-turbolinks="false">
<a href="/myLicense" class="nav-link{{$_SERVER['REQUEST_URI'] == '/myLicense' ? ' active' : ''}}">My License</a>
</li>
<li class="nav-item" style="font-size: 12px;" data-turbolinks="false">
<a href="/userLicense/d6a1a836-b0a9-4e0e-987a-af6cec0a6c29" class="nav-link{{$_SERVER['REQUEST_URI'] == '/userLicense/d6a1a836-b0a9-4e0e-987a-af6cec0a6c29' ? ' active' : ''}}">User License</a>
</li>
@endif
</ul>
<ul class="navbar-nav justify-content-end">
<li class="nav-item">
<a class="nav-link" href="https://developer.microsoft.com/graph/docs/concepts/overview" target="_blank">
<i class="fas fa-external-link-alt mr-1"></i>Docs
</a>
</li>
@if(isset($userName))
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button"
aria-haspopup="true" aria-expanded="false">
@if(isset($user_avatar))
<img src="{{ $user_avatar }}" class="rounded-circle align-self-center mr-2" style="width: 32px;">
@else
<i class="far fa-user-circle fa-lg rounded-circle align-self-center mr-2" style="width: 32px;"></i>
@endif
</a>
<div class="dropdown-menu dropdown-menu-right">
<h5 class="dropdown-item-text mb-0">{{ $userName }}</h5>
<p class="dropdown-item-text text-muted mb-0">{{ $userEmail }}</p>
<div class="dropdown-divider"></div>
<a href="/signout" class="dropdown-item">Sign Out</a>
</div>
</li>
@else
<li class="nav-item">
<a href="/signin" class="nav-link">Sign In</a>
</li>
@endif
</ul>
</div>
</div>
</nav>
<main role="main" class="container">
@if(session('error'))
<div class="alert alert-danger" role="alert">
<p class="mb-3">{{ session('error') }}</p>
@if(session('errorDetail'))
<pre class="alert-pre border bg-light p-2"><code>{{ session('errorDetail') }}</code></pre>
@endif
</div>
@endif
@yield('content')
</main>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
<!-- Styles -->
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Nunito', sans-serif;
font-weight: 200;
height: 100vh;
margin: 0;
}
.full-height {
height: 100vh;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.top-right {
position: absolute;
right: 10px;
top: 18px;
}
.content {
text-align: center;
}
.title {
font-size: 84px;
}
.links > a {
color: #636b6f;
padding: 0 25px;
font-size: 13px;
font-weight: 600;
letter-spacing: .1rem;
text-decoration: none;
text-transform: uppercase;
}
.m-b-md {
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
@if (Route::has('login'))
<div class="top-right links">
@auth
<a href="{{ url('/home') }}">Home</a>
@else
<a href="{{ route('login') }}">Login</a>
@if (Route::has('register'))
<a href="{{ route('register') }}">Register</a>
@endif
@endauth
</div>
@endif
<div class="content">
<div class="title m-b-md">
Laravel
</div>
<div class="links">
<a href="https://laravel.com/docs">Docs</a>
<a href="https://laracasts.com">Laracasts</a>
<a href="https://laravel-news.com">News</a>
<a href="https://blog.laravel.com">Blog</a>
<a href="https://nova.laravel.com">Nova</a>
<a href="https://forge.laravel.com">Forge</a>
<a href="https://vapor.laravel.com">Vapor</a>
<a href="https://github.com/laravel/laravel">GitHub</a>
</div>
</div>
</div>
</body>
</html>
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::get('/', 'HomeController@welcome');
Route::get('/signin', 'MicrosoftGraphController@signin');
Route::get('/callback', 'MicrosoftGraphController@callback');
Route::get('/signout', 'MicrosoftGraphController@signout');
Route::get('/calendar', 'CalendarController@calendar');
//get details of the current user
Route::get('/me', 'MicrosoftGraphController@getMyInfo');
//get all users
Route::get('/users', 'MicrosoftGraphController@getAllUsers');
//get all joinedTeams
Route::get('/joinedTeams', 'MicrosoftGraphController@getMyTeams');
//get all groups
Route::get('/groups', 'MicrosoftGraphController@getAllGroups');
//get members of a team
Route::get('/membersOfTeam/{groupId}', 'MicrosoftGraphController@getTeamMembers');
//get team info
Route::get('/teamInfo/{groupId}', 'MicrosoftGraphController@getTeamInfo');
//get my license details
Route::get('/myLicense', 'MicrosoftGraphController@getMyLicense');
//get user license details
Route::get('/userLicense/{userId}', 'MicrosoftGraphController@getUserLicense');
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment