lvr123 lvr123 - 4 months ago 61
Java Question

Getting a OneNote token with Java

I fail to get a valid OneNote token from Java (in a desktop application).

I think I may not understand the whole process of authorization through an application. But I can't find information that clears this up.

Here is the Java code I use:

HttpsURLConnection refreshTokenConnection;
refreshTokenConnection = (HttpsURLConnection) (new URL(TOKEN_REQUEST_URL)).openConnection();
refreshTokenConnection.setDoOutput(true);
refreshTokenConnection.setRequestMethod("POST");
refreshTokenConnection.setDoInput(true);
refreshTokenConnection.setRequestProperty("Content-Type", TOKEN_REFRESH_CONTENT_TYPE);
refreshTokenConnection.connect();

String redirect = URLEncoder.encode(TOKEN_REFRESH_REDIRECT_URL, "UTF-8");

try (OutputStream refreshTokenRequestStream = refreshTokenConnection.getOutputStream()) {
String requestBody = MessageFormat.format(TOKEN_REFRESH_REQUEST_BODY,
Constants.CLIENTID, redirect, ACCESS_SCOPE);
System.out.println(requestBody);
refreshTokenRequestStream.write(requestBody.getBytes());
refreshTokenRequestStream.flush();
} catch (Exception ex) {
System.err.println("while writing request body");
ex.printStackTrace();
}

if (refreshTokenConnection.getResponseCode() == 200) {
return parseRefreshTokenResponse(refreshTokenConnection);
}
else {
throw new Exception("The attempt to refresh the access token failed");
}


The response I get is an html reponse telling me that "Microsoft account is experiencing technical problems. Please try again later" !

<!-- ServerInfo: BL2IDSLGN1H030 2015.12.15.14.26.46 Live1 ExclusiveNew LocVer:0 -->
<!-- PreprocessInfo: BTSA007:RR1BLDF009, -- Version: 16,0,26014,0 -->
<html dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<base href="https://login.live.com/pp1600/"/>


<title>Microsoft account</title>
<meta name="PageID" content="i4400">
<meta name="SiteID" content="38936">
<meta name="ReqLC" content="1033">
<meta name="LocLC" content=" ">
<style type="text/css">
body {
background-color: #fff;
color: #000;
font-family: "Segoe UI","Segoe UI Web Regular","Segoe UI Symbol","Helvetica Neue","BBAlpha Sans","S60 Sans",Arial,sans-serif;
font-weight: 400;
font-size: 15px;
line-height: 20px;
}
h1 {
line-height: 56px;
font-weight: 200;
margin: 20px 0;
}
h2 {
font-size: 34px;
font-weight: 200;
line-height: 40px;
padding: 3.18px 0;
}
p {
margin: 12px 0;
padding: 0.22px 0;
}
.header, .content {
width: 90%;
margin: 0 auto;
}
.logo {
vertical-align: middle;
}
.site-identifier {
line-height: 23px;
font-size: 17px;
margin-left: 15px;
padding-left: 15px;
border-left: 1px solid #aaa;
color: #aaa
}
.footer {
margin-top: 100px;
}
</style>
<script type="text/javascript">
function EndPPCRL(rs, u)
{
if (external)
{
try
{
if (rs)
{
external.RequestStatus = rs;
external.WebFlowUrl = u;
external.NotifyIdentityChanged();
external.ReturnToApp();
}
else
{
external._cW(); external.BrowseToAuthUI();
}
}
catch (e) { }
}
}
function BodyLoad()
{
EndPPCRL(-2147186656);
}
</script>
<script type="text/javascript">
WizardExternalHelper = function(){ };
WizardExternalHelper.prototype =
{
setProperty: function(key, value)
{
try
{
window.external.Property(key) = value;
}
catch (e) { }
},
finalNext: function()
{
try
{
window.external.FinalNext();
}
catch (e) { }
}
};
</script>
<script type="text/javascript">
try
{
var channelMessage =
{
type: "event",
value:
{
name: "CloudExperienceHost.done",
data: "fail"
}
};
window.external.notify(JSON.stringify(channelMessage));
} catch (e) {};
try
{
var externalHelper = new WizardExternalHelper();
externalHelper.setProperty("ExtendedErrorString", "");
externalHelper.setProperty("ErrorCode", parseInt(1));
externalHelper.setProperty("ErrorString", "This service isn't available right now—please try again later.");
externalHelper.finalNext();
} catch (e) {};
function OnBack() {};
function OnNext() {};
</script>
</head>
<body onLoad="BodyLoad()">
<div class="header" id="idHeaderTD9">
<h1>
<img src="images/ms-logo-v2.jpg" class="logo" alt=" " />
<span class="site-identifier">Account</span>
</h1>
</div>
<div class="content">
<h2>We're unable to complete your request</h2>
<p>Microsoft account is experiencing technical problems. Please try again later.</p>
</div>
</body>
</html>
<!-- _i-Agent:Java/1.8.0_45 -->


Although If I'm using the same url directly in a browser, I'm redirected to a page where I must log-on and the accept the requested rights. From there, I received the tolken I'm looking for.

This is this latter step I'm failing to understand how to programmaticaly achieve : requiring the acceptance from the user.

== EDIT : OkHttp version ==

The code that brings me a step further:

private final String ACCESS_SCOPE = "office.onenote";
private final String TOKEN_REQUEST_URL = "https://login.live.com/oauth20_authorize.srf";
private final String TOKEN_REFRESH_REDIRECT_URL = "https://login.live.com/oauth20_desktop.srf";

HttpUrl base = HttpUrl.parse(TOKEN_REQUEST_URL);

HttpUrl hurl;
HttpUrl.Builder urlBuilder = new HttpUrl.Builder();
urlBuilder.scheme(base.scheme());
urlBuilder.port(base.port());
urlBuilder.host(base.host());
urlBuilder.encodedPath(base.encodedPath());
urlBuilder.encodedQuery(base.encodedQuery());

// response_type=token&client_id={0}&redirect_uri={1}&scope={2}
urlBuilder.addQueryParameter("response_type", "token");
urlBuilder.addQueryParameter("client_id", Constants.CLIENTID);
urlBuilder.addQueryParameter("redirect_url", TOKEN_REFRESH_REDIRECT_URL);
urlBuilder.addQueryParameter("scope", ACCESS_SCOPE);
hurl = urlBuilder.build();

Request request = new Request.Builder().url(hurl).build();

Response response = client.newCall(request).execute();


The response's body:

<!DOCTYPE html><!-- ServerInfo: BL2IDSLGN3C026 2015.12.15.14.26.46 Live1 Unknown LocVer:0 -->
<!-- PreprocessInfo: BTSA007:RR1BLDF009, - Version: 16,0,26014,0 -->
<!-- RequestLCID: 1033, Market:EN-US, PrefCountry: US, LangLCID: 1033, LangISO: EN -->
<html dir="ltr" lang="EN-US"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=Edge"/><base href="https://login.live.com/pp1600/"/><script type="text/javascript">var PROOF = {};PROOF.Type = {SQSA: 6, CSS: 5, DeviceId: 4, Email: 1, AltEmail: 2, SMS: 3, HIP: 8, Birthday: 9, TOTPAuthenticator: 10, RecoveryCode: 11, StrongTicket: 13, TOTPAuthenticatorV2: 14, Voice: -3};</script><noscript><meta http-equiv="Refresh" content="0; URL=https://login.live.com/jsDisabled.srf?mkt=EN-US&lc=1033"/>Microsoft account requires JavaScript to sign in. This web browser either does not support JavaScript, or scripts are being blocked.<br /><br />To find out whether your browser supports JavaScript, or to allow scripts, see the browser's online help.</noscript><title>Sign in to your Microsoft account</title><meta name="PageID" content="i5030"/><meta name="SiteID" content="279469"/><meta name="ReqLC" content="1033"/><meta name="LocLC" content="1033"/><link rel="shortcut icon" href="https://auth.gfx.ms/16.000.26014.00/favicon.ico?v=2" />
<link rel="stylesheet" title="R3CSS" type="text/css" href="https://auth.gfx.ms/16.000.26014.00/R3WinLive1033.css"/><style type="text/css"></style><style type="text/css">body{display:none;}</style><script type="text/javascript">if (top != self){try{top.location.replace(self.location.href);}catch (e){}}else{document.write(unescape('%3C%73') + 'tyle type="text/css">body{display:block !important;}</style>');}</script><noscript><style type="text/css">body{display:block !important;}</style></noscript><script type="text/javascript">var g_iSRSFailed=0,g_sSRSSuccess="";function SRSRetry(a,f,b){var e=1,d=unescape('%3Cscript type="text/javascript" src="'),c=unescape('"%3E%3C/script%3E');if(g_sSRSSuccess.indexOf(a)!=-1)return;if(typeof window[a]=="undefined"){g_iSRSFailed=1;b<=e&&document.write(d+f+c)}else g_sSRSSuccess+=a+"|"+b+","}
var g_dtFirstByte=new Date();var g_objPageMode = null;</script><link rel="image_src" href="https://auth.gfx.ms/16.000.26014.00/Windows_Live_v_thumb.jpg" / >
<script type="text/javascript">var ServerData = {aU:'microsoft.com,https://corp.sts.microsoft.com/adfs/ls/?cbcxt=&vv=&username=&mkt=&lc=,urn:federation:MSFT|idcrltestns.com,http://p2.live.com/auth/federation/wsfederator.aspx?Action=login&Domain=idcrltestns.com&cbcxt=&vv=&username=&mkt=&lc=,Test IDCRL Federation Partner',urlSwitch:'https://login.live.com/logout.srf?response_type=token&client_id=000000004017D35F&redirect_url=https://login.live.com/oauth20_desktop.srf&scope=office.onenote&ru=http://oauth.live.net&bk=1451775130&lm=I&pid=15216',aV:"Sign in to .",Bf:1000,AR:false,sCBUpTxt1:'',Bh:'https://auth.gfx.ms/16.000.26014.00/AppCentipede/AppCentipede_Microsoft.png',aX:"Use the primary phone number you\'ve associated with your Microsoft account. <a href=\"http://explore.live.com/windows-live-sign-in-single-use-code-faq\" id=\"idPaneHelpOTCInfoLink9\" target=\"_blank\">Learn more</a>",m:true,AT:0,AU:{},sCBUpTxt2:'',Bi:'',n:false,o:'Pass',AW:'',p:'https://login.live.com/cookiesDisabled.srf?mkt=EN-US&lc=1033',q:true,AX:'https://go.microsoft.com/fwlink/?LinkID=254486',sFedQS:'wa=wsignin1.0&wtrealm=uri:WindowsLiveID&wctx=response_type%3Dtoken%26client_id%3D000000004017D35F%26redirect_url%3Dhttps://login.live.com/oauth20_desktop.srf%26scope%3Doffice.onenote%26bk%3D1451775130',A:true,v:'',B:false,ab:'',urlPost:'https://login.live.com/ppsecure/post.srf?response_type=token&client_id=000000004017D35F&redirect_url=https://login.live.com/oauth20_desktop.srf&scope=office.onenote&bk=1451775130&uaid=4c7c1337346b4a0fb64b97945c57a0f4&pid=15216',C:true,html:[],ad:'',D:1,str:[],a0:'4c7c1337346b4a0fb64b97945c57a0f4',F:'https://account.live.com/ResetPassword.aspx?wreply=https://login.live.com/oauth20_authorize.srf%3fresponse_type%3dtoken%26client_id%3d000000004017D35F%26redirect_url%3dhttps://login.live.com/oauth20_desktop.srf%26scope%3doffice.onenote%26bk%3d1451775130&id=279469&uiflavor=web&client_id=1E00004017D35F&uaid=4c7c1337346b4a0fb64b97945c57a0f4&mkt=EN-US&lc=1033&bk=1451775130',Ab:{'Logo':'','LogoAltText':'','LogoText':'','ShowWLHeader':true},a1:'https://account.live.com/query.aspx?mkt=EN-US&lc=1033',BA:false,sErrTxt:'',ag:true,a2:'',a3:'',H:'https://signup.live.com/signup.aspx?response_type=token&client_id=000000004017D35F&redirect_url=https://login.live.com/oauth20_desktop.srf&scope=office.onenote&bk=1451775130&ru=https://login.live.com/oauth20_authorize.srf%3fresponse_type%3dtoken%26client_id%3d000000004017D35F%26redirect_url%3dhttps://login.live.com/oauth20_desktop.srf%26scope%3doffice.onenote%26mkt%3dEN-US%26lc%3d1033%26bk%3d1451775130&uiflavor=web&uaid=4c7c1337346b4a0fb64b97945c57a0f4&mkt=EN-US&lc=1033',BC:true,a4:'',A0:true,BD:false,I:false,Ae:false,a5:'',oPost:{},urlFed:'',J:'response_type=token&client_id=000000004017D35F&redirect_url=https://login.live.com/oauth20_desktop.srf&scope=office.onenote&bk=1451775130',Af:0,A1:false,a6:'',BF:"Sign in",K:3,Ah:'',a7:'https://login.live.com/gls.srf?urlID=WinLiveTermsOfUse&mkt=EN-US&vv=1600',A3:false,M:'',BI:'https://auth.gfx.ms/16.000.26014.00/Microsoft_Logotype_Gray.png',A5:true,Ak:false,Al:1,P:'',Am:'##li16####B##Hotmail##/B####BR##The smart way to do email - fast, easy and reliable##li8####B##Messenger##/B####BR##Stay in touch with the most important people in your life##li10####B##SkyDrive##/B####BR##Free, password-protected online storage',A9:'',urlLogin:'https://login.live.com/oauth20_authorize.srf?response_type=token&client_id=000000004017D35F&redirect_url=https://login.live.com/oauth20_desktop.srf&scope=office.onenote&bk=1451775130&mkt=EN-US&lc=1033',Ap:'',av:"#~#partnerdomain#~# does\'t use this service. Please sign in with a Microsoft account or create a new account. <a href=\"#~#WLPaneHelpInviteBlockedURL_LS#~#\" id=\"idPaneHelpInviteBlockedLink9\">Learn More</a>",V:'',ax:"A single-use code lets you sign in without entering your password. This helps protect your account when you\'re using someone else\'s PC. <a href=\"http://explore.live.com/windows-live-sign-in-single-use-code-faq\" id=\"idPaneHelpOTCInfoLink9\" target=\"_blank\">Learn more</a>",aD:'https://login.live.com/gls.srf?urlID=MSNPrivacyStatement&mkt=EN-US&vv=1600',urlFedConvertRename:'https://account.live.com/security/LoginStage.aspx?lmif=1000&ru=https://login.live.com/oauth20_authorize.srf%3Fresponse_type%3Dtoken%26client_id%3D000000004017D35F%26redirect_url%3Dhttps://login.live.com/oauth20_desktop.srf%26scope%3Doffice.onenote%26vv%3D1600%26loginfmt%3Dconctact_lvr%2540live.com%26mkt%3DEN-US%26lc%3D1033&response_type=token&client_id=000000004017D35F&redirect_url=https://login.live.com/oauth20_desktop.srf&scope=office.onenote&vv=1600&loginfmt=conctact_lvr%40live.com&mkt=EN-US&lc=1033',ay:"Your session has timed out. To request a single use code, please <a href=\"javascript:NewOTCRequest()\">refresh the page</a>.",Y:true,Av:{},AA:{},aE:'',aF:2,Ax:'https://sc.imp.live.com/content/dam/imp/surfaces/mail_signin/v3/account/EN-US.html?id=279469&mkt=EN-US',Ay:'https://login.live.com/oauth20_authorize.srf?response_type=token&client_id=000000004017D35F&redirect_url=https://login.live.com/oauth20_desktop.srf&scope=office.onenote&mkt=EN-US&lc=1033&bk=1451775130',aI:true,AE:false,AF:"&copy;2016 Microsoft",sFTTag:'<input type="hidden" name="PPFT" id="i0327" value="DU2pRBKzRt7SzTHFM8igJwfODysa55R!ae1QZKYjexw1LLykan8u*bWZY83DjD37TbjlzVYQFFtP0PKHJ8up07drqwdOKsxwVDsn9n4be5u0oCzUyAEI1srL!hJNzzLCNCSTCyQA0oPQUd*R4!TP6Vfkc5TDWdTxKEV9aGCxstqeQFB28eikXz1M!gVZ7FyK2Q$$"/>',AG:'https://auth.gfx.ms/16.000.26014.00/',sPOST_NewUser:'',AH:0,aL:true,b:'',aO:0,e:'',aP:1033,AM:'sign up',Ba:'',f:'',aS:'',Bc:false,AO:'',Bd:true};</script><script type="text/javascript" src="https://auth.gfx.ms/16.000.26014.00/Login_Strings_JS1033.js"></script>
<script type="text/javascript" src="https://auth.gfx.ms/16.000.26014.00/Login_Core.js"></script>
<script type="text/javascript">SRSRetry("__Login_Strings", "https://auth.gfx.ms/16.000.26014.00/Login_Strings_JS1033.js", 1);SRSRetry("__Login_Core", "https://auth.gfx.ms/16.000.26014.00/Login_Core.js", 1);</script><script type="text/javascript">SRSRetry("__Login_Strings", "https://auth.gfx.ms/16.000.26014.00/Login_Strings_JS1033.js", 2);SRSRetry("__Login_Core", "https://auth.gfx.ms/16.000.26014.00/Login_Core.js", 2);</script></head>
<body onload="evt_Login_onload(event);" uiTheme="Web">
</body></html>


And my app's API Settings:

Mobile or desktop client app:

Yes

Restrict JWT issuing:

Yes

Enhanced redirection security:

Enabled

Target domain:

Redirect URLs:

Answer

The fact is that the authentication process requires a user interaction. It cannot be done by calling directly the url but by loading the url in a browser.

Here is illustrated the 2 steps authentification :

1) Get a temporary code, through user interaction;

2) Get a tolken with that code.

This example uses OkHttp for direct Http calls, Gson for json manipulation. And MozSwing as browser.

private final static Pattern PATTERN_EXTRACT = Pattern.compile(".*code=(.*)$", Pattern.CASE_INSENSITIVE);
private final static String GETCODE_URL = "https://login.live.com/oauth20_authorize.srf?response_type=code&display=touch&client_id=%s&redirect_url=https://login.live.com/oauth20_desktop.srf&scope=office.onenote";

/*
* Step (1) : get a valide code through user interaction
*/
public void requestCode() {

    SwingUtilities.invokeLater(() -> {
        String url = String.format(GETCODE_URL, _the_application_id_);
        browser.load(url);
    });
}

/**
* Called when the browser triggers an event locationChanged()
*/
public void locationChanged() {
    final String location = browser.getUrl();
    Matcher m = PATTERN_EXTRACT.matcher(location);
    if (m.matches() && m.groupCount() == 1) {
        setCode(m.group(1));
    }
}

/**
* Step (2) : get a valid tolken based on the newly aquired code
*/
void setCode(String code) {
    try {

        RequestBody formBody = new FormEncodingBuilder()
                .add("client_id", _the_application_id_)
                .add("redirect_url", TOKEN_REFRESH_REDIRECT_URL)
                .add("client_secret", _the_application_secret_)
                .add("code", code)
                .add("grant_type", "authorization_code")
                .build();

        Request.Builder reqBuilder = new Request.Builder();
        reqBuilder.url(TOKEN_REFRESH_URL);
        reqBuilder.post(formBody);

        Request request = reqBuilder.build();

        final Call call = client.newCall(request);

        // exécution en synchrone
        Response response = call.execute();

        JsonObject refreshTokenResponse = UrlHelper.parseResponse(response);
        final JsonPrimitive at = refreshTokenResponse.getAsJsonPrimitive("access_token");
        if (at != null) {
            setTolken(at.getAsString());
            setStatus(Status.DONE);
            return true;
        }

    } catch (Exception ex) {
        // TODO : add some error handling
        ex.printStackTrace();
    }
}


/**
 * Parse a OneNote HTTP reponse and returns its data as a JSonObject
 *
 * @param response
 *
 * @return
 */
public static JsonObject parseResponse(Response response) {
    final String body;

    try {
        body = response.body().string();
    } catch (IOException ex) {
        throw new InvalidOnenoteContentExcepion("Unable to retrieve response content", ex);
    }

    if (!response.isSuccessful()) {
        if (response.body().contentType().toString().startsWith("application/json")) {
            JsonObject message = ZJsonReader.getInstance().from(body);
            throw new ApiException(message, response.code(), response.message());
        }
        else {
            throw new HttpException(response.code(), response.message());

        }

    }
    if (response.body().contentType().toString().startsWith("application/json")) {
        JsonObject refreshTokenResponse = ZJsonReader.getInstance().from(body);
        return refreshTokenResponse;
    }
    System.err.println(body);
    throw new InvalidOnenoteContentExcepion("Invalid response content :\"" + response.body().contentType().toString() + "\"");
}