I would like to access the global address book of an organization through outlook rest api
I was able to implement the Single Sign-on part using OAUTH2 but I'm unable to understand how to access the contacts object
I have gone through this
and many other examples but unable to understand how to implement them in PHP
Firstly, if you want to use the rest api to access the outlook contacts, at the moment, Microsoft suggests customers use the Microsoft Graph. For more details, please refer to the document
Secondly, regarding how to get outlook conatcts with php application, you need to use oauth2-client to add Azure AD authentication and get Azure AD access token then call the api to get contacts with the access token. For example, please refer to the following steps to know how to implement it in php web application
Register Azure AD application
Configure app permissions you need for your application
Implement Azure AD authentication with the SDK oauth2-client
a. Create a .env file
OAUTH_APP_ID=YOUR_APP_ID_HERE
OAUTH_APP_PASSWORD=YOUR_APP_PASSWORD_HERE
OAUTH_REDIRECT_URI=<your redirect url>
OAUTH_SCOPES='openid profile offline_access' + <your need outlook permissions>
OAUTH_AUTHORITY=https://login.microsoftonline.com/common
OAUTH_AUTHORIZE_ENDPOINT=/oauth2/v2.0/authorize
OAUTH_TOKEN_ENDPOINT=/oauth2/v2.0/token
b. Get access token
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class AuthController 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
]);
return redirect()->route('contacts');
}
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'));
}
}
```
Use the access token With Microsoft Graph SDK. For more details, please refer to the docuemnt
public function mail()
{
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
$tokenCache = new \App\TokenStore\TokenCache;
$graph = new Graph();
$graph->setAccessToken($tokenCache->getAccessToken());
$contacts = $graph->createRequest('GET', '/me/contacts/{Id}')
->setReturnType(Model\Contact::class)
->execute();
}
Regarding the details of how to implement it, please refer to the sample
Besides, if you want to call the outlook rest api with php, please refer to the document. But please note that you need to change the app permissions.
Related
I'm still a newbie and want to ask about the task I'm working on,
in this case I'm making authentication using oauth2 to be able to access apple api,
but i have an error when signin using apple, invalid_client appears,
for invalid_client error, I've done the following way:
check the client_id used in the http request (doubts) (i've try by changing client_id)
adjust the jwt header and jwt payload to the parameters requirements (checked)
and check the JWT signature (checked)
of the three steps that I tried, I felt doubt in the script authentication or client id
please tell me where my fault is in the client_id naming or in the script section
thank you for the help, sorry for my bad english here I include the script that I use
``
$provider = new Apple([
'clientId' => 'com.example.example',
'teamId' => 'apple-team-id',
'keyFileId' => 'apple-key-file-id',
'keyFilePath' => storage_path('apple-key-file-path'),
'redirectUri' => 'http://localhost:8000/Store/Gold_Store/GoldStore-create',
]);
if(!isset($_POST['code'])){
//jika kita tidak mempunyai authorization code
$authUrl = $provider->getAuthorizationUrl();
$_SESSION['oauth2state'] = $provider->getState();
header('Location: '.$authUrl);
exit;
//check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_POST['state']) || ($_POST['state'] !== $_SESSION['oauth2state'])) {
unset($_SESSION['oauth2state']);
exit('Invalid state');
}else{
//try to get access token(using the authorization code grant)
$token = $provider->getAccessToken('authorization_code', [
'code' => $_POST['code']
]);
//Optional: Now u have a token u can look up a user profile data
try {
//we got an access token, lets now get the user's detail
$user = $provider->getResourceOwner($token);
//use these details to create a new profile
printf('hello %s!', $user->getFirstName());
//refresh token
$refreshToken = $token->getRefreshToken();
$refreshTokenExpiration = $token->getRefreshTokenExpires();
} catch (Exception $e) {
//Failed to get user details
exit(':-(');
}
//use this to interact with an API on the users behalf
echo $token->getToken();
}
this is my json result
``{
"error": "invalid_client"
}
invalid_client error mean the client secret is wrong, maybe the issue in how you generate it or the details which you used.
You can check this snipped of code to test PHP apple sign in
https://gist.github.com/ameen-sarsour/e14a1d5bae5b61080dfdd5b1430c3e10
I'm currently trying to implement a way to synchronize my PHP App calendar with the Outlook calendar of my clients, using Azure API.
I use OAuth2 and the custom Microsoft provider by Steven Maguire.
I currently run in an issue where I get an error in my response :
{"error":"unsupported_grant_type","error_description":"The provided value for the input parameter 'grant_type' is not valid. Expected values are the following: 'authorization_code', 'refresh_token'."}
I'm having trouble understanding why the grant_type password is not supported, even though it says on the documentation of Azure that it is.
The request looks like this :
client_id=44bef79b-**********************&client_secret=H****************&redirect_uri=https%3A%2F%2F192.168.1.123%2Fmapeyral%2Fcalendarsync.php&grant_type=password&username=******************&password=***********&scope=openid%20profile%20offline_access%20Calendars.ReadWrite
The Authorize url used is : https://login.live.com/oauth20_token.srf
as defined in the Steven Maguire provider.
The header contains the content-type application/x-www-form-urlencoded (I've seen a lot of post where this was what caused the error).
Some of my code :
$this->provider = new Microsoft([
'clientId' => MicrosoftGraphConstants::CLIENT_ID,
'clientSecret' => MicrosoftGraphConstants::CLIENT_SECRET,
'redirectUri' => MicrosoftGraphConstants::REDIRECT_URI,
'urlAuthorize' => MicrosoftGraphConstants::AUTHORITY_URL . MicrosoftGraphConstants::AUTHORIZE_ENDPOINT,
'urlAccessToken' => MicrosoftGraphConstants::AUTHORITY_URL . MicrosoftGraphConstants::TOKEN_ENDPOINT,
'urlResourceOwnerDetails' => MicrosoftGraphConstants::RESOURCE_ID,
'scope' => MicrosoftGraphConstants::SCOPES
]);
if ($_SERVER['REQUEST_METHOD'] === 'GET' && !isset($_GET['code']))
{
// Try getting access token from Database
$workingAccount = $GLOBALS['AppUI']->getState('working_account');
if (isset($workingAccount))
{
// DB access
$DB = new DatabaseConnection();
$dbAccess = $DB->getConnection();
$contactData = DBUserUtils::getContactDataFromEmail($GLOBALS['AppUI']->getState('working_account'), $dbAccess);
// If at least one user contact found
if (!is_null($contactData))
{
// If has refresh token => fill session variables using refresh token
if (!is_null($contactData['contact_refreshToken']))
{
log_msg('debug.log', 'Has refresh token');
$GLOBALS['AppUI']->setState('preferred_username', $contactData['contact_email']);
$GLOBALS['AppUI']->setState('given_name', $contactData['contact_first_name']." ".$contactData['contact_last_name']);
// Get new tokens
$newAccessToken = $this->provider->getAccessToken('refresh_token', [
'refresh_token' => $contactData['contact_refreshToken']
]);
// Update tokens and DB
$GLOBALS['AppUI']->setState('refresh_token', $newAccessToken->getRefreshToken());
$GLOBALS['AppUI']->setState('access_token', $newAccessToken->getToken());
DBOAuthUtils::updateTokenForUser($contactData['contact_id'], $GLOBALS['AppUI']->getState('refresh_token'), $dbAccess);
$this->redirectTo($redirectURL);
}
else
{
$this->getAccessToken();
}
}
else
{
$this->getAccessToken();
}
}
else
{
$this->getAccessToken();
}
function getAccessToken(){
$accessToken = $this->provider->getAccessToken('password', [
'username' => '*************',
'password' => '********',
'scope' => MicrosoftGraphConstants::SCOPES
]);
}
During the first try it doesn't pass the if (isset($workingAccount)) condition (as expected) and go straight to the last else.
Code is a bit ugly for now but I don't think it has an impact on my problem.
Any help would be appreciated !
Thanks
Edit : added code
That helped me, the problem was that I need to use Azure Active Directory and not Azure AD 2.0.
Problem solved !
I am trying to use the Admin-paterson oauth library for PHP to connect to slack
(https://github.com/adam-paterson/oauth2-slack)
When I run the sample code:
include("slack-vendor/autoload.php");
include("slacker/src/Provider/Slack.php");
$provider = new \AdamPaterson\OAuth2\Client\Provider\Slack([
'clientId' => $$slackid,
'clientSecret' => $slacksecret,
'redirectUri' => $returnURL,
]);
if (!isset($_GET['code'])) {
// If we don't have an authorization code then get one
$authUrl = $provider->getAuthorizationUrl();
$_SESSION['oauth2state'] = $provider->getState();
header('Location: '.$authUrl);
exit;
// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
unset($_SESSION['oauth2state']);
exit('Invalid state');
} else {
// Try to get an access token (using the authorization code grant)
$token = $provider->getAccessToken('authorization_code', [
'code' => $_GET['code']
]);
// Optional: Now you have a token you can look up a users profile data
try {
// We got an access token, let's now get the user's details
$team = $provider->getResourceOwner($token);
// Use these details to create a new profile
printf('Hello %s!', $team->getName());
} catch (Exception $e) {
// Failed to get user details
exit('Oh dear...');
}
// Use this to interact with an API on the users behalf
echo $token->getToken();
}
I get an error back from slack saying :
Invalid permissions requested
Requested scopes cannot be blank
I tried adding a "scope" to the call like this:
$provider = new \AdamPaterson\OAuth2\Client\Provider\Slack([
'clientId' => $slackid,
'clientSecret' => $slacksecret,
'redirectUri' => $returnURL,
'scope' => 'channels:write,groups:write,team:read'
]);
but it still returns the same error.
When I look at the url the scope field is blank
what do I need to do to send scope to the server?
Add your scope in getAuthorizationUrl() method like this
$authUrl = $provider->getAuthorizationUrl([
'scope' => 'channels:write'
]);
use the scope as defined in https://api.slack.com/apps/ in your App, under OAuth, e.g. 'scope' => 'users.profile:read'
I'm facing problems fetching data (Profile list to be specific) from google analytics. The credentials like client_id, secret etc are in place and it does allow user to login successfully, but I'm stuck in the next step where I need to fetch the list of profiles (list of websites). I did go through the official docs as per Google Views (Profiles): list but while I try it, I get an error:
Undefined property: App\Http\Controllers\UserController::$analytics
the detailed error:
in UserController.php line 84
at HandleExceptions->handleError('8', 'Undefined property: App\Http\Controllers\UserController::$analytics', 'C:\xampp\htdocs\Laravel Projects\testApp\app\Http\Controllers\UserController.php', '84', array('request' => object(Request), 'google_redirect_url' => 'http://localhost:8000/glogin', 'gClient' => object(Google_Client), 'google_oauthV2' => object(Google_Service_Oauth2), 'guser' => null, 'user' => object(User), 'token' => array('access_token' => 'TOKEN GOES HERE', 'token_type' => 'Bearer', 'expires_in' => '3600', 'id_token' => 'ID_TOKEN GOES HERE', 'created' => 'CREATED DATA GOES HERE'))) in UserController.php line 84
I do understand there's an error when I try to fetch the data, but then I don't really understand as to how should i be doing that. Anyone has any idea? Please help!
here's the Controller
class UserController extends Controller
{
public function googleLogin(Request $request) {
$google_redirect_url = route('glogin');
$gClient = new \Google_Client();
$gClient->setApplicationName(config('services.google.app_name'));
$gClient->setClientId(config('services.google.client_id'));
$gClient->setClientSecret(config('services.google.client_secret'));
$gClient->setRedirectUri($google_redirect_url);
$gClient->setDeveloperKey(config('services.google.api_key'));
$gClient->addScope(\Google_Service_Analytics::ANALYTICS_READONLY);
$gClient->addScope("email");
$gClient->addScope("profile");
$gClient->setAccessType("offline");
$google_oauthV2 = new \Google_Service_Oauth2($gClient);
if ($request->get('code')){
$gClient->authenticate($request->get('code'));
$request->session()->put('token', $gClient->getAccessToken());
}
if ($request->session()->get('token'))
{
$gClient->setAccessToken($request->session()->get('token'));
}
if ($gClient->getAccessToken())
{
//For logged in user, get details from google using access token
$guser = $google_oauthV2->userinfo->get();
$request->session()->put('name', $guser['name']);
if ($user =User::where('email',$guser['email'])->first())
{
}else{
//register your user with response data
return User::create([
'name' => $guser->name,
'email' => $guser->email,
]);
}
//LINE NO 84 is below:
$profiles = $this->analytics->management_profiles
->listManagementProfiles();
$accounts = $accountsObject->getItems();
return $accounts;
//return redirect()->route('user.glist');
} else
{
//For Guest user, get google login url
}
}
}
You are calling $this->analytics but nowhere do you define the property analytics for the UserController class. Not sure what is defined in the parent class Controller but I am pretty sure it is agnostic of the Analytics service object.
You need to instantiate the Google_Service_Analytics object.
// Create an authorized analytics service object.
$analytics = new Google_Service_Analytics($gclient);
See the Hello Analytics guide for details.
I am using an OAuth plugin in my php application. All works well when I use all the code in one function. But I want split the OAuth call, and the OAuth token treatment. I try to create a global var for the provider object, but it doesn't work. I always have an error with the $provider object.
This is the function I have for the moment :
function login(){
$provider = new Stevenmaguire\OAuth2\Client\Provider\Microsoft([
'clientId' => 'myclientid',
'clientSecret' => 'mysecret',
'redirectUri' => 'https://mywebsite'
//'redirectUri' => 'https://mywebsite/loginMicrosoft' //The url where I want use the token
]);
if (!isset($_GET['code'])) {
$authUrl = $provider->getAuthorizationUrl();
$this->Session->write('oauth2state', $provider->getState());
// This is the part I want put in the function loginMicrosoft. All else if and else
} elseif (empty($_GET['state']) || ($_GET['state'] !== $this->Session->read('oauth2state'))) {
$this->Session->destroy();
exit('Invalid state');
} else {
// Try to get an access token (using the authorization code grant)
$token = $provider->getAccessToken('authorization_code', [
'code' => $_GET['code']
]);
// Use this to interact with an API on the users behalf
$this->log( $token->getToken());
}
}
//This is the function where I want put the elseif and else treatment
function loginMicrosoft (){
}
Thanks for your help.
EDIT : I also try to put my provider object in session, but I have the message "Call to a member function getAccessToken() on a non object"
EDIT 2 : After unsuccessfully tried, I keep all the OAuth code in the same function