Hero Banner

Secure Application Model

Learn and ask questions on how to implement secure application model

Visitor 1

Partner Portal REST Authentication?


I'm a bit new to the partner portal REST interface so I might be missing something, but I'm able to generate an access token, but any subsequent calls fail due to 401?  I'm assuming that if I was able to generate a token I should be able to interact with these resources?  The current authentication instructions seem to indicate that this should work, but it looks like there may have been some changes?

POST /v1/validations/address HTTP/1.1
Host: api.partnercenter.microsoft.com
Authorization: Bearer token
Content-Type: application/json
MS-Contract-Version: v1
MS-RequestId: 2ed90876-94d7-451f-a7e8-f3f7cdf932b5
MS-CorrelationId: 3eb8b7f7-9b0f-4c75-8d55-b1d17565b6cb
X-Locale: en-US
Cache-Control: no-cache
Postman-Token: 5d2ae072-2d10-ca30-8f33-587942f3bcfd

AddressLine1: "One Microsoft Way",
City: "Redmond",
State: "WA",
PostalCode: "98052",
Country: "US"

Visitor 1

Re: Partner Portal REST Authentication?

What endpoints are you using to aquire tokens? and have you shiftet to the new "secure app model"? you are posting in that section, but since you ask if theres a change, thought I should ask

Visitor 1

Re: Partner Portal REST Authentication?


Migrating to the new secureapp model  for the app  with partnercenter access (Using /oauth2/token not oauth2/v2.0/token)

- Using the Token obtained with AppID AppSecret I can call https://api.partnercenter.microsoft.com/generatetoken providing my graph token  and I get a token that works to read customer info

- Using the Token obtained using the refreshToken obtained following and Authorize and providing Consent for the same App  -  I get a an 401 Unauthorized

1) I noted that token obtained with the endpoint oauth2/v2.0 are invalid to https://api.partnercenter.microsoft.com/generatetoken

2) Token content are similar as far of roles

3) scope used was:scope=https://api.partnercenter.microsoft.com/.default&offline_access%20Device.ReadWrite.All%20Directory.Read.All%20Directory.AccessAsUser.All%20Directory.ReadWrite.All%20User.Read%20User.Read.All%20User.ReadBasic.All





Re: Partner Portal REST Authentication?

Hi @pierre_lestage,

Use of the GenerateToken request has been deprecated, it is recommended that you update your code to not perform that operation. Also, through my experience I have better results using the Azure AD v1 endpoints because of compatibility issues with things like pre-consent. The Partner Center Authentication documentation should guide you through this. Please let us know if you have any concerns or questions.

Visitor 1

Re: Partner Portal REST Authentication?


I'm trying to use the REST API to build an app to manage actions on Partner Center Portal. 


I'm using Python and I don't know how to build the REST API to get the token. This is an example of the code I'm using.


It always return "404"... so I'm a little bit frustrated. Maybe is my fault but I cannot find any example to build this correctly.


Any help will be greatly appreciated. BR and thx a lot in advance!


# tenantid, appid and secret are all obtained following the instructions on different sources, so all of them are ok


post_address = "https://login.microsoftonline.com/{tenantId}/oauth2/token HTTP/1.1".format(
tenantId = configuracionCSP["tenantid"] )


resource_address = "https://graph.windows.net&client_id={client_id}&client_secret={client_secret}&grant_type=client_credentials".format(
client_id = configuracionCSP["appid"],
client_secret = configuracionCSP["secret"]


headers = {
"Accept" : "application/json",
'MS-Contract-Version' : "api-version: v1",
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
"Host": "login.microsoftonline.com"


res = requests.post( 
data={"resource" : resource_address},
allow_redirects = True)

Level 5 Contributor

Re: Partner Portal REST Authentication?

@youngluke , mine isn't in Python, but here's what I use to connect in Javascript - maybe it will help? The languages are close enough you should be able to see what I'm doing and adapt to Python.


// NOTE: api.get() and api.post() are convience wrapper functions around standard GET and POST functions in:
const request = require("request-promise")

// Partner Center - LIVE/Real Connection (not Integration Sandbox)
function connectPartnerCenter() {
	// The RefreshToken expires (by default) 90 days from when it was generated, so the current one is stored in a "Password Vault"
	// (A separate scheduled function takes care of renewing it as needed)
	let pcRefreshToken = api.get("NAME OF VAULT", 'Current PartnerCenter RefreshToken')
	let tenantID = "companyName.com"					// Our LIVE CSP / Partner Center domain (the long GUID version of the Tenant ID also works fine)
	let authRequest = {
		resource: "https://api.partnercenter.microsoft.com",
		grant_type: 'refresh_token',
		refresh_token:  pcRefreshToken,	
		scope: "openid",
		// These are all for the LIVE/Real CSP Partner Center:
		// !! IMPORTANT: When these are updated you must ALSO update the Renew-PartnerCenterRefreshTokens function
		// NOTE: These were created using the process here, if I recall:
		// https://www.microsoftpartnercommunity.com/t5/Secure-Application-Model/Exchange-Online-and-the-Secure-App-Model/m-p/15421/highlight/true#M125
		client_id: "f728xxx-etc-etc-etc-xxxx98946",		// the NativeApp AppID gives "AppPlusUser" rights WITH MFA (via some UPN )
		client_secret: "XF+zetcetctec-long-key-etcetcetciyUkylk="		// the NativeApp Key / Shared Secret, expires 1 or 2 years after creation
	let authResponse = api.post("customForm", 		// implies {form: requestJsonObject}  (as opposed to body: requestJsonObject)
		"https://login.microsoftonline.com/" + tenantID + "/oauth2/token",
	// Basic check, but more likely the above api.post() will fail if there's something wrong
	if (authResponse.token_type != "Bearer" && authResponse.scope != "user_impersonation") {
		console.log("ERROR Obtaining access_token! The refresh_token may have expired or need to be reacquired. Or the client_secret may have expired.\nThe OAuth results are:\n")
		throw "Token_Type not Bearer or Scope not User_Impersonation."

	let partnerCenterHeaders = {
		'Accept': "application/json; charset=utf-8",
		'MS-Contract-Version': "v1",
		'MS-PartnerCenter-Application': "Our company name and this scriptname, for reference",
		'X-Locale': "en-US"
	// Update global variable with BearerToken for future connections, which are used by our api.XXX() wrapper functions
	// in other parts of the script (to do the "Real" work)
	apiDefaultsPartnerCenter = request.defaults({
		baseUrl: "https://api.partnercenter.microsoft.com/",
		json: true,
		encoding: 'utf8',				// without this the returned data has UNICODE 65279 (shows as '?') prefixed and isn't decoded correctly
		headers: partnerCenterHeaders,
		auth: {
			bearer: authResponse.access_token		// AccessToken is only valid for 60 mins, if scripts take longer would need to break them up

// There-after we can we the apiDefaultsPartnerCenter object in our api.get() or api.post() functions as apiDefaultsPartnerCenter contains
// the correct URL and auth header, etc. So then we'd do, for example:
let orgProfile = api.get(apiDefaultsPartnerCenter, "v1/profiles/organization")	// and it would join baseUrl + "v1/profiles/organization", etc

Maybe it helps see the Oauth and then Bearer token and how we call thereafter?