OAuth authorization_code flow unauthorized unless done via Postman - oauth-2.0

I'm trying to get an application to work with the Microsoft Identity platform.
Sending an OAuth request via Postman appears to work, but when I try the authorizaton_code grant type myself, despite getting back an access token, the API that I'm trying to access always gives me an unauthorized error.
I'm sending a POST request to:
https://login.windows.net/<tenant_id>/oauth2/authorize?resource=<resource_uri>
With body data:
grant_type=authorization_code&
client_id=<client_id>&
redirect_uri=<redirect_uri>&
response_type=code
This gives me a redirect to my URI with the code in the querystring
I then request an access token with the code by sending a POST to:
https://login.windows.net/<tenant_id>/oauth2/token?resource=<resource_uri>
With the following content:
grant_type=authorization_code&
client_id=<client_id>&
redirect_uri=<redirect_uri>&
code=<the_code_from_the_redirect>&
client_secret=<client_secret>
This gives me back an access token:
{
"token_type": "Bearer",
"expires_in": "3599",
"ext_expires_in": "3599",
"expires_on": "1557783183",
"not_before": "1557779283",
"resource": "00000002-0000-0000-c000-000000000000",
"access_token": "<access_token_here>",
"refresh_token": "<refresh_token>",
"id_token": "<id_token>"
}
But this token doesn't work when calling the resource:
{
"error": {
"code": "Unauthorized",
"message": "The credentials provided are incorrect"
}
}
Doing the same using the Get New Access Token functionality in Postman seems to create the same post request in the Postman console (albeit with a different code, but it has to get a new code because I've already redeemed the other one and it knows nothing about it right?) but the access token that it returns works:
{
"error": {
"code": "NoLicense",
"message": "User has no license"
}
}
(Ignore the fact that it's an error - the user has no licence for the application I'm trying to query but that's ok)
Am I doing something fundamentally wrong? From what I can see, I'm following the OAuth flow correctly.

Figured this out - it's because I was passing the resource as part of the querystring and not part of the form.
When the identity platform generates the redirect/callback it only appears to include either the querystring elements when doing a GET or the form elements when doing a POST.
You can see that in the below:
<html>
<head>
<title>Continue</title>
</head>
<body>
<form method="POST" name="hiddenform" action="https://login.microsoftonline.com/<tenant_id>/oauth2/authorize">
<input type="hidden" name="grant_type" value="authorization_code" />
<input type="hidden" name="client_id" value="<client_id>" />
<input type="hidden" name="redirect_uri" value="https://businesscentral.dynamics.com" />
<input type="hidden" name="response_type" value="code" />
<input type="hidden" name="scope" value="" />
<noscript>
<p>Script is disabled. Click Submit to continue</p>
<input type="submit" value="Submit" />
</noscript>
</form>
<script language="javascript">window.setTimeout('document.forms[0].submit()', 0);</script>
</body>
</html>
After adding resource to the form data instead of the URL I got a slightly different redirect:
<html>
<head>
<title>Continue</title>
</head>
<body>
<form method="POST" name="hiddenform" action="https://login.microsoftonline.com/<tenant_id>/oauth2/authorize">
<input type="hidden" name="grant_type" value="authorization_code" />
<input type="hidden" name="client_id" value="<client_id>" />
<input type="hidden" name="redirect_uri" value="https://businesscentral.dynamics.com" />
<input type="hidden" name="response_type" value="code" />
<input type="hidden" name="scope" value="" />
<input type="hidden" name="resource" value="<resource_id>" />
<noscript>
<p>Script is disabled. Click Submit to continue</p>
<input type="submit" value="Submit" />
</noscript>
</form>
<script language="javascript">window.setTimeout('document.forms[0].submit()', 0);</script>
</body>
</html>
Which generated me the correct access token!

Related

Messenger Bot: Webview form action

I have a chatbot and I want to use webview forms when the "survey" is "non-linear"
I have this form. What to "place" in the action if I want to tell the bot to catch the data?
<form action="I SEARCHING FOR THIS" method="GET">
<input type="text" name="foo" placeholder="foo" />
<input type="text" name="bar" placeholder="bar" />
<button type="submit">SUBMIT</button>
</form>
Action should be sent to the URL for your webhook. Also, if you are sending data you should POST not GET.

Submitting form through iframe: Rails 4 InvalidAuthenticityToken in Chrome, Safari

I have a form on a page which other people can embed through an iframe on their sites. When submitting that form I get an ActionController::InvalidAuthenticityToken error, in Safari and also Chrome (with third-party cookies turned off) but not in Firefox.
My understanding was that I don't have to rely on third-party cookies being activated if I've got this in my header:
<head>
<%= csrf_meta_tags %>
</head>
But apparently that's not true...?
And I'm even seeing the token in my server log:
Parameters: {"utf8"=>"✓", "authenticity_token"=> "2ig3BPn9...
Can't verify CSRF token authenticity
So what's going on here?
From the ActionController::RequestForgeryProtection docs:
Controller actions are protected from Cross-Site Request Forgery (CSRF) attacks by including a token in the rendered HTML for your application. This token is stored as a random string in the session, to which an attacker does not have access. When a request reaches your application, Rails verifies the received token with the token in the session.
So even if you embed the token with csrf_meta_tags you still need it also in the session (i.e. in the cookie). That's why with disabled third-party cookies it doesn't work in the iframe.
into form insert:
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>"/>
Ex:
<form name="as" target="open_here" method="get" action="material">
<input type="hidden" name="materialid" value="56"/>
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>"/>
<input type="submit" value="Submit open_here" />
</form>
or
<form name="unit" target="open_here" method="get" action="/redmine/issues_materials/material" >
<input type="hidden" id="material_id" name="materialid" value="" /><!-- valo value e inputado pelo script 2 document.getElementById('material_id').value = materialid; -->
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>"/> <!-- para funcionar tem que enviar essa chave junto-->
<input id="idunit" type="submit" value="open here submit" style="display: none;"/>
</form>
<iframe id="open_here" name="open_here" frameborder="0" scrolling="no" width="60" height="80"></iframe>

MVC Display Data

Following this MVC Tutorial, but cannot get the display customer view to display after input the data. I don't see anything I do wrong
http://www.codeproject.com/Articles/207797/Learn-MVC-Model-View-Controller-step-by-step-in-7
here is my fill customer
<div>
<form action="DisplayCustomer.aspx" method="post">
Enter Customer Code: <input type="text" name="CustomerCode" /><br />
Enter Customer Name: <input type="text" name="CustomerName" /><br />
Ennter Customer Amout: <input type="text" name="CustomerAmount" /><br />
<input type="submit" value="Submit customer data" />
</form>
</div>
here is my display customer
public ActionResult DisplayCustomer()
{
Customer localCustomer = new Customer();
localCustomer.Code = Request.Form["CustomerCode"].ToString();
localCustomer.Name = Request.Form["CustomerName"].ToString();
localCustomer.Amount = Convert.ToDouble(Request.Form["CustomerAmount"].ToString());
return View(localCustomer);
}
then
<div>
The name of the customer is: <%:Model.Name = "test" %>
<br />
The code of the customer is: <%:Model.Code %>
<br />
The amout refund to the customer is: <%:Model.Amount%>
</div>
seems like something is wrong with the steps
I got this error when I tried
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /customer/DisplayCustomer.aspx
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.17929
The correct path for the request is /customer/displaycustomer
The .aspx extension gets handled in a different way, so the MVC Routing Engine is never fired, and as that page doesn't exist at that path the result is a 404 error.
You actually need to remove .aspx extension. Just request the page as /Customer/DisplayCustomer.
As a side note, you may need to update your form aswell and remove the aspx extension, eg:
<form action="DisplayCustomer" method="post">
Enter customer id :- <input type="text" name="Id" /> <br />
Enter customer code :- <input type="text" name="CustomerCode" /><br />
Enter customer Amount :-<input type="text" name="Amount" /><br />
<input type="submit" value="Submit customer data" />
</form>
replaced the line:
<form action="DisplayCustomer.aspx" method="post">
to
<form action="DisplayCustomer" method="post">

How do you upload files directly to S3 over SSL?

I've been using browser based direct POST uploads with Amazon S3 for a while, and just recently wanted to start posting through HTTPS. Normal HTTP posts work just fine. However, when I post the same form to https://s3.amazonaws.com/, I get a "405 Method Not Allowed".
Do browser based direct AWS POST uploads not support HTTPS? If they do, how can I do it without getting a 405 error?
Thanks!
It could be some problem with your HTML FORM action.
The action specifies the URL that processes the request, which must be set to the URL of the
bucket. For example, if the name of your bucket is "johnsmith", the URL
is "http://johnsmith.s3.amazonaws.com/".
Please check this AMAZON S3 documentation link for more detail:
http://docs.amazonwebservices.com/AmazonS3/latest/dev/HTTPPOSTForms.html#HTTPPOSTFormDeclaration
There is also a another post on this.
Amazon S3 - HTTPS/SSL - Is it possible?
UPDATE:
I was able to upload objects to S3 bucket over SSL using this HTML & Policy.Check the form action.
Policy :
{
"expiration": "2012-06-04T12:00:00.000Z",
"conditions": [
{"bucket": "<YourBucketName>" },
{"acl": "public-read" },
["eq", "$key", "testImage.jpg"],
["starts-with", "$Content-Type", "image/jpeg"],
]
}
HTML:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<form action="https://s3.amazonaws.com/<YourBucketName>/" method="post" enctype="multipart/form-data">
<input type="text" name="key" value="testImage.jpg" />
<input type="text" name="acl" value="public-read" />
<input type="text" name="content-type" value="image/jpeg" />
<input type="hidden" name="AWSAccessKeyId" value="<YOUR ACCESS KEY>" />
<input type="hidden" name="policy" value="<YOUR GENERATED POLICY>" />
<input type="hidden" name="signature" value="<YOUR GENERATED SIGNATURE>" />
<input name="file" type="file" />
<input name="submit" value="Upload" type="submit" />
</form>
</body>
</html>
You must know how to generate encoded policy and signature.

Multiple Scope Values to oauth2

I try to post several scope values to allow my application for some google service...
I tried with two input field
<input type="hidden" name="scope" value="https://www.googleapis.com/auth/calendar" />
<input type="hidden" name="scope" value="https://www.googleapis.com/auth/userinfo.email" />
and with one input field with + separator
<input type="hidden" name="scope" value="https://www.googleapis.com/auth/calendar+https://www.googleapis.com/auth/userinfo.email" />
When I send my form with only one scope It work.
otherwise with sereval scope value google redirect me with this error description :
http://localhost:49972/redirect.aspx#error=invalid_request&error_description=OAuth+2+parameters+can+only+have+a+single+value:+scope&error_uri=http://code.google.com/apis/accounts/docs/OAuth2.html
In the google getting started with oAuth2 it works with two scope values.
Here is my code :
<form id="form1" method="post" action="https://accounts.google.com/o/oauth2/auth?" >
<div>
<input type="hidden" name="response_type" value="code" />
<input type="hidden" name="client_id" value="my client id" />
<input type="hidden" name="redirect_uri" value="http://localhost:49972/redirect.aspx" />
<input type="hidden" name="scope" value="https://www.googleapis.com/auth/calendar" />
<input type="hidden" name="scope" value="https://www.googleapis.com/auth/userinfo.email" />
<input type="hidden" name="state" value="/profile" />
<input type="submit" value="go" />
</div>
</form>
You were on the right track when you combined them to a single field
. There should be only one scope parameter in the request, with the values separated by spaces. If you're putting it in a form like that, the browser will take care of encoding the space for you.
<input type="hidden" name="scope" value="https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/userinfo.email" />
In addition to Steve Bazyl's answer. When applying multiple scopes for the same Google service, order of scopes seems to matter. F.e this string works as expected:
"https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.metadata.readonly"
while this one does not work for me:
"https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/drive"
I have not found any information about that in the docs though.
You can put all scopes in 1 array for clarity:
const scopes = [
'openid',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/gmail.readonly',
]
const scope = scopes.join(' ')
console.log(scope)
// openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/gmail.readonly
const redirectUri = 'http://localhost:3000'
const link = `https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=${scope}&response_type=code&client_id=${GOOGLE.clientId}&redirect_uri=${redirectUri}&state=authGoogle`

Resources