Hi,
i created a page to check the settings for implit grants in portals. You can also acquire a token with additional parameters. This token can be checked for validity on jwt.io or jwt.ms.
May be, this is also helpful for s.o. else.
Even if i usually do not recommend to do so, just paste the code into a new page with a full page template for example and it should work out of the box. Of course, you can also create a web template with that content and use it via a pagetemplate on a page.
Have fun and feel free to get in touch with me,
Christian
PS yes, it's not the most beautiful art work in the world, but it fits my requirements 🙂
{% assign enabledsettingname = "Connector/ImplicitGrantFlowEnabled" %}
{% assign thumbtrintsettingname = "CustomCertificates/ImplicitGrantflow" %}
{% assign clientidssettingname = "ImplicitGrantFlow/RegisteredClientId" %}
{% assign tokenexpirationsettingname = "ImplicitGrantFlow/TokenExpirationTime" %}
{% assign delimeter = ";" %}
{% assign implicitgrant_enabled = settings[enabledsettingname] | boolean | default: true %}
{% assign implicitgrant_thumbprint = settings[thumbtrintsettingname] %}
{% assign implicitgrant_clientidsraw = settings[clientidssettingname] %}
{% assign implicitgrant_tokenexpirationsetting = settings[tokenexpirationsettingname] %}
{% assign clientids = implicitgrant_clientidsraw | split: delimeter %}
<style>
input::placeholder {
opacity: 0.5;
}
.spaceontop {
padding-top: 5px;
}
.aslabel {
font-weight: bold;
}
</style>
<div class="row">
<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Why this page? :-)</h3>
</div>
<div class="panel-body">
This is a short testpage, whether acquiring a token for implicit grant is correctly set up for this site. For informations about how to set this up please consider
visiting <a href="https://learn.microsoft.com/en-us/power-pages/security/oauth-implicit-grant-flow" target="_blank">Microsoft docs Implit grant in portals</a>.
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Settings</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-xs-12 aslabel">Public key of portal</div>
</div>
<div class="row">
<div class="col-xs-12" id="publickey"></div>
</div>
{% if user %}
<div class="row spaceontop">
<div class="col-xs-6 aslabel">Implicit grant enabled? ({{enabledsettingname}})</div>
<div class="col-xs-6">{{implicitgrant_enabled}}</div>
</div>
<div class="row spaceontop">
<div class="col-xs-6 aslabel">Thumbrint of certificate ({{thumbtrintsettingname}})</div>
<div class="col-xs-6">{{implicitgrant_thumbprint}}</div>
</div>
<div class="row spaceontop">
<div class="col-xs-6 aslabel">Tokenexpiration ({{tokenexpirationsettingname}})</div>
<div class="col-xs-6">{{implicitgrant_tokenexpirationsetting}}</div>
</div>
<div class="row spaceontop">
<div class="col-xs-6 aslabel">Available clientids ({{clientidssettingname}})</div>
<div class="col-xs-6">{{implicitgrant_clientidsraw}}</div>
</div>
{% for clientid in clientids %}
{% assign redirkey = "ImplicitGrantFlow/" | append: clientid | append: "/RedirectUri" %}
{% assign redirecturisrow = settings[redirkey] | default: "" %}
<div class="row spaceontop">
<div class="col-xs-6 aslabel">Redirects {{clientid}} ({{redirkey}})</div>
<div class="col-xs-6">{{redirecturisrow}}</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>
</div>
</div>
{% if user %}
<div class="row">
<div class="col-xs-12">
<div class="input-group">
<span class="input-group-addon">request nounce</span>
<input type="text" class="form-control" id="nouncesrc" placeholder="input nounce for request here">
</div>
</div>
</div>
<div class="row spaceontop">
<div class="col-xs-12">
<div class="input-group">
<span class="input-group-addon" id="clientid-addon">request clientid</span>
<select class="form-control" id="clientidsrc">
<option></option>
{% if implicitgrant_clientidsraw %}
{% for clientid in clientids %}
<option value="{{clientid}}">{{clientid}}</option>
{% endfor %}
{% endif %}
</select>
<!--
<input type="text" class="form-control" placeholder="input clientid for request here" id="clientidsrc">
-->
</div>
</div>
</div>
<div class="row spaceontop">
<div class="col-xs-12">
<div class="input-group">
<span class="input-group-addon" id="redirecturi-addon">request Redirect Uri</span>
<select class="form-control" id="redirecturisrc">
<option></option>
{% if implicitgrant_clientidsraw %}
{% for clientid in clientids %}
{% assign redirkey = "ImplicitGrantFlow/" | append: clientid | append: "/RedirectUri" %}
{% assign redirecturisrow = settings[redirkey] | default: "" %}
{%if redirecturisrow %}
{% assign redirecturis = redirecturisrow | split: delimeter %}
{% for redirecturi in redirecturis %}
<option value="{{redirecturi}}">{{redirecturi}} ({{clientid}})</option>
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
</select>
<!-- <input type="text" class="form-control" placeholder="input Redirect Uri for request here" id="redirecturisrc">-->
</div>
</div>
</div>
<div class="row spaceontop">
<div class="col-xs-12">
<div class="input-group">
<span class="input-group-addon" id="state-addon">request state</span>
<input type="text" class="form-control" placeholder="input state for request here" id="statesrc">
</div>
</div>
</div>
<div class="row spaceontop">
<div class="col-xs-2">
<button type='button' onclick="showToken('#token','#expiresin','#state','#requri','#clientidsrc','#redirecturisrc','#statesrc','#nouncesrc')">get token</button>
</div>
</div>
<div class="row spaceontop">
<div class="col-xs-12">
<div class="input-group">
<span class="input-group-addon" id="requri-addon">Uri of post request</span>
<span class="form-control" aria-describedby="requri-addon" id="requri"></span>
</div>
</div>
</div>
<div class="row spaceontop">
<div class="col-xs-12">
<div class="input-group">
<span class="input-group-addon" id="expiresin-addon">expires in (from responseheader)</span>
<span class="form-control" aria-describedby="expiresin-addon" id="expiresin"></span>
</div>
</div>
</div>
<div class="row spaceontop">
<div class="col-xs-12">
<div class="input-group">
<span class="input-group-addon" id="state-addon">returned state (from responseheader)</span>
<span class="form-control" id="state"></span>
</div>
</div>
</div>
<div class="row spaceontop">
<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Token from response</h3>
</div>
<div class="panel-body" id="token" style="overflow-wrap: break-word;">
</div>
</div>
</div>
</div>
<div class="row spaceontop">
<div class="col-xs-12">
The above token can be checked and verified (with the public key) on <a href="https://jwt.io" target="_blank">jwt.io</a> or checked on <a href="https://jwt.ms" target="_blank">jwt.ms</a>
</div>
<div class="col-xs-12">
You may also wish to consult <a href="/_services/about" target="_blank">/_services/about</a> in order to view the portalinfo or clearing the cache beeing logged in as an administrator.
</div>
</div>
{% else %}
<div class="row">
<div class="col-xs-12">
please log in to acquire a token
</div>
</div>
{% endif %}
<script language="javascript">
async function getToken(client_id,redirect_uri,state,nonce) {
var params = [
["client_id",client_id]
,["redirect_uri",redirect_uri]
,["state",state]
,["nonce",nonce]
]
.filter(([key,value]) => value && typeof(value) != "undefined")
.map(([key,value]) => `${key}=${value}`)
.join("&");
var requrl = `/_services/auth/token${params.length > 0 ? "?" : ""}${params}`;
var tr = await fetch(requrl,{method:"post"});
var token = await tr.text();
var rstate = tr.headers.get("state");
var rexpires_in = tr.headers.get("expires_in");
return [token, rexpires_in, rstate, requrl];
}
async function getPublicKey() {
var pkreq = await fetch("/_services/auth/publickey");
var pk = await pkreq.text();
return pk;
}
function showResult(result, targetElement) {
var te = null;
if(targetElement) {
te = document.querySelector(targetElement);
}
if(te) {
te.innerText = result;
} else {
console.log(result);
}
}
async function showPublicKey(targetElement) {
var pk = await getPublicKey();
showResult(pk, targetElement);
}
async function showToken(tokenTargetElement, expires_inTargetElement, stateTargetElement, requriTargetElement, clientidsrc, redirecturisrc, statesrc,nouncesrc) {
var clientid = clientidsrc ? document.querySelector(clientidsrc)?.value : null;
var redirecturi = redirecturisrc ? document.querySelector(redirecturisrc)?.value : null;
var state = statesrc ? document.querySelector(statesrc)?.value : null;
var nounce = nouncesrc ? document.querySelector(nouncesrc)?.value : null;
showResult("", tokenTargetElement);
showResult("", expires_inTargetElement);
showResult("", stateTargetElement);
showResult("", requriTargetElement);
var [token, expires_in, state, requri] = await getToken(clientid,redirecturi,state,nounce);
showResult(token, tokenTargetElement);
showResult(expires_in, expires_inTargetElement);
showResult(state, stateTargetElement);
showResult(requri, requriTargetElement);
}
showPublicKey("#publickey");
</script>