Twitter OAuth "Could not authenticate you" when I specify a callback url - c#

I'm having an issue with Twitter OAuth 1.0 during the request_token stage
If I set a oauth_callback of oob (or even omit the callback url) then it works fine, but then of course doesnt redirect the user to my web app afterwards.
N.B. I may be going about this the wrong way. I just want to specify a URL that the client browser should be directed to after having authorized the OAuth request on Twitter
As soon as I change the oauth_callback to my app's callback url, I get the error "Could not authenticate you"
I have setup the callback url in the app settings on twitter to exactly the same url as the one I am settings in the oauth_callback parameter of the request_token process which FYI is an HTTPS base url i.e. no path specified, https://www.example.com/
Any assistance would be appreciated
UPDATE
This request works (no callback url specified at all):
POST https://api.twitter.com/oauth/request_token HTTP/1.1
Authorization: OAuth oauth_consumer_key="----myconsumerkey----", oauth_nonce="r70s1926", oauth_signature="iFGmXEpDav0lVpge9Ls9ACGI6r0%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1503053275", oauth_version="1.0"
This request does not (callback url specified, same as twitter app setting):
POST https://api.twitter.com/oauth/request_token HTTP/1.1
Authorization: OAuth oauth_callback="https%3A%2F%2Fwww.example.com", oauth_consumer_key="----myconsumerkey----", oauth_nonce="707n8282", oauth_signature="0KWzeJwQ%2FNMfmdZ%2Bt0zNEU4g3Ag%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1503053306", oauth_version="1.0"
The request above returns:
{"errors":[{"code":32,"message":"Could not authenticate you."}]}

Because exclusion or a setting of oob works it sounds like an encoding problem within the signature generation.
Check that the oauth_callback url is double encoded within your signature base string which should look something like:
POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttps%253A%252F%252Fwww.example.com%26oauth_consumer_key%3Dmyconsumerkey%26oauth_nonce%3D707n8282%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1503057157%26oauth_version%3D1.0

Related

Unable to Validate JWT or access_token in API with IdentityServer4

I'm working on building out some new functionality where we have an existing system. Our goal is to have different Angular SPA's communicate with APIs to present a new interface for our legacy app. A team has set up IdentityServer4 to use the legacy application for credentials verification.
The SPA, written in Angular 7, uses the implicit flow to authenticate. Response type is "token id_token" I've been able to get this flow to work insomuch as I can have an unauthenticated user come to the site, get kicked over to the IdentityServer authentication screens, log in with correct credentials, and then redirected back to the app. When I get the token back the claims object has a single value for aud, the client_id for the SPA, for example, spa-client. The access_token and id_token are both a JWT with RS256 as the signature method. Lastly, I've created an interceptor in the SPA to send the JWT (in actuality it just uses whatever value is sent back as the access_token) as the "Bearer" token on API requests.
I have now created a .NET Core 2.2 WebApi app to build out a service API to be consumed by the SPA. This app uses the IdentityServer4.AccessTokenValidation package to "protect" the API I've read the section in the IdentityServer4 docs. In my ConfigureServices method I've written the following to configure auth:
services
.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
if (string.IsNullOrWhiteSpace(serviceConfiguration.Authentication.Authority)) throw new ConfigurationException("", nameof(serviceConfiguration.Authentication.Authority), "An authority must be defined.");
if (string.IsNullOrWhiteSpace(serviceConfiguration.Authentication.ApiName)) throw new ConfigurationException("", nameof(serviceConfiguration.Authentication.ApiName), "An api name must be defined.");
options.Authority = serviceConfiguration.Authentication.Authority;
options.ApiName = serviceConfiguration.Authentication.ApiName;
if (!string.IsNullOrWhiteSpace(serviceConfiguration.Authentication.ApiSecret))
{
options.ApiSecret = serviceConfiguration.Authentication.ApiSecret;
}
options.RequireHttpsMetadata = false;
options.SupportedTokens = SupportedTokens.Both;
}
serviceConfiguration is a strongly type representation of my JSON appsettings.json
My understanding is that with options.SupportedTokens = SupportedTokens.Both will check the JWT and do introspection.
Now that all this is setup I've taken the simple example ValuesController that is created by the API template and added the [Authorize] attribute to it. Doing a simple GET request to this endpoint in Postman returns a 401 as I would expect.
Next I try logging into the SPA and going to a test page which will do the same but with the interceptor will have the bearer token, the access_token, or basically the JWT. I still get a 401 from the service.
Looking at the logs output by the service I don't see anything specific that is helpful:
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 OPTIONS http://localhost:5001/api/values info:
Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 OPTIONS http://localhost:5001/api/values info:
Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
CORS policy execution successful. info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
CORS policy execution successful. info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 61.1352ms 204 info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 61.1272ms 204 info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5001/api/values application/json info:
Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5001/api/values application/json info:
Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
CORS policy execution successful. info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
CORS policy execution successful. info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'Examples.TestApp.API.Web.Controllers.ValuesController.Get
(Examples.TestApp.API.Web)' info:
Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'Examples.TestApp.API.Web.Controllers.ValuesController.Get
(Examples.TestApp.API.Web)' info:
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "Get", controller = "Values"}. Executing action
Examples.TestApp.API.Web.Controllers.ValuesController.Get
(Examples.TestApp.API.Web) info:
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "Get", controller = "Values"}. Executing action
Examples.TestApp.API.Web.Controllers.ValuesController.Get
(Examples.TestApp.API.Web) info:
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed. info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed. info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. info:
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. info:
Microsoft.AspNetCore.Mvc.ChallengeResult[1]
Executing ChallengeResult with authentication schemes (). info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
Executing ChallengeResult with authentication schemes (). info: IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler[12]
AuthenticationScheme: Bearer was challenged. info: IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler[12]
AuthenticationScheme: Bearer was challenged. info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action Examples.TestApp.API.Web.Controllers.ValuesController.Get
(Examples.TestApp.API.Web) in 166.3038ms info:
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action Examples.TestApp.API.Web.Controllers.ValuesController.Get
(Examples.TestApp.API.Web) in 162.8827ms info:
Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'Examples.TestApp.API.Web.Controllers.ValuesController.Get
(Examples.TestApp.API.Web)' info:
Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'Examples.TestApp.API.Web.Controllers.ValuesController.Get
(Examples.TestApp.API.Web)' info:
Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 459.6677ms 401 info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 473.7648ms 401
Setting the logging to Trace didn't reveal anything else.
I did try going to Postman to see if I could do introspection on the token manually. I set up authorization to basic and set the Username to "test-api", the api id, and the password that I set in its client secret. In the body a set it to x-www-form-urlencoded with a key of "token" and the value the access_token. I get a 200 OK with claims along with "active: true". Seems like that should be good, right?
I don't own the IdentityServer implementation so I'm not quite sure what's going on at that end except for being able to log into the admin UI. I've logged into the admin UI for the identity server and double checked the settings for the client and the API. The client gets granted a "api" scope and the API gets the same scope "api". This is shown in the scope that is sent back in the introspection response as well as the token that I get from the client.
I've also tried setting the options.SupportedTokens = SupportedTokens.Reference and options.SupportedTokens = SupportedTokens.JWT. Neither had any change. :(
What am I doing wrong? Is this a configuration issue or me being an idiot (probably the latter).
EDIT: RE access_token and id_token
I was incorrect in the original question. The tokens are different (I need to look at more than just the header portion).
The audiences are weird. I've never paid attention to a possible difference here when decoding. My powers of perception must suck!
The access token has aud: "http:///resources"
The id_token has aud: "spa-client"
The access_token and id_token are both the same and are a JWT with RS256 as the signature method.
The access_token and id_token should not the same . For id_token the audclaim in token should be the name of the client , but in access token , your api name should be include in the aud , so that your api resource could validate that the access token is issued to make "my" api calls. You can use online tool like jwt.io to decode the claims in JWT tokens . Since you haven't post the configuration of client & IDS4 , you should check the response type,scope ... If using Fiddler to trace the request , it should like :
GET /connect/authorize/callback?client_id=js&redirect_uri=http%3A%2F%2Flocalhost%3A5003%2Fcallback.html&response_type=id_token%20token&scope=openid%20profile%20api1&state=xxxxxxxxxxxxxxx&nonce=xxxxxxxxxxxxxxxxxxx
In addition , from document : http://docs.identityserver.io/en/latest/topics/grant_types.html
For JavaScript-based applications, Implicit is not recommended anymore. Use Authorization Code with PKCE instead.
You can click here for code flow code sample .
Update :
the audience of access token should also include api name , apart from "http:///resources :
You could click here for code samples .

Fetch OAuth token from ebay api

I'm developing a web application to to fetch data from 'https://api.ebay.com/sell/analytics/v1/traffic_report'
I've a ebay developer account with
ClientId: MyClientId
ClientSecret: MyClientSecret
AppId: MyAppId
To achive this, I need a OAuth token
To get OAuth Token I do the following steps.
I browse the url bellow
https://signin.ebay.com/authorize?client_id=MyClientId&redirect_uri=RuName&response_type=code&state=analytics&scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.analytics.readonly
It goes to
https://signin.ebay.com/ws/eBayISAPI.dll?VAppJanessa&reqinput=reqinput - auto generate
after sign in it redirects to 'Grant application access to MySiteDisplayName' page.
After I Agree it redirects to 'https://my_site.com/?state=analytics&code=code'
I've preapared a post request after collecting the code
I've executed the post request using POSTMAN like bellow
Post URL: 'https://api.ebay.com/identity/v1/oauth2/token'
Headers:
cache-control: no-cache
Content-Type: application/x-www-form-urlencoded
Authorization: Basic Base64 value of 'MyClientId:MyClientSecret'
Body:
grant_type: authorization_code
redirect_uri: RuName
code: code returned from previous request
After post request I've got the result
{
"error": "invalid_grant",
"error_description": "the provided authorization grant code is invalid or was issued to another client"
}
Please tell me what is missing or wrong.
Looks like clientId and appId you are sending don't match each other, probably one is a production one and another being a developer one. Happened with me once.
If there are multiple apps being registered, each with its own appId under the same clientId, many times the client Secret Gets missed. Try checking the correct combination of all three.

GET request works in browser, but I get Unauthorized when using Postman

I am issuing a request via chrome:
[org]/api/data/v8.1/accounts?$select=name,accountid&$top=3
and I get a reasonable response:
{
"#odata.context":"[org]/api/data/v8.1/$metadata#accounts(name,accountid)","value":[
{
"#odata.etag":"W/\"769209\"","name":"Telco","accountid":"c6ed63e0-9664-e411-940d-00155d104b35"
},{
"#odata.etag":"W/\"752021\"","name":"Fourth Coffee","accountid":"d1eefc0a-3ebc-e611-80be-24be051ac8a1"
},{
"#odata.etag":"W/\"768036\"","name":"Fourth Coffee","accountid":"3cbb8d24-20bd-e611-80c0-24be051ac8a1"
}
]
}
However, when attempting to do the same GET through postman, I am getting a 401 unauthorized!
I've tried with no headers at all, as well as basic auth:
Authorization:Basic Y2hybGFiXxxxxxxxxxxxxxcmQxMjM=
What am I doing wrong? Is there something I need to change within CRM to allow me to do GETs from postman?
The following are headers that Chrome uses (got this from DevTools):
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Authorization:Negotiate
TlRMTVNTUAADAAAAGAAYAIoAAABkAWQBogAAAAwADABYAAAADgAOAGQAAAAYABgAcgAAABAAEAAGAgAAFYKI4gYBsR0AAAAPai35LURprYMgYVSwMQXi/2MAaAByAGwAYQBiAGEAZwBvAHIAZABvAG4ASABPAFUALQBXAFMALQBBAEcATwBSAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd0avVN8acJQKvlSN8hYrSgEBAAAAAAAAoBg7uZi80gEIIthtN5clBAAAAAACAAYARABFAFYAAQAUAEIAQQBOAEMAUgBNADIAMAAxADYABAAcAGQAZQB2AC4AYwBoAHIAbABhAGIALgBpAG4AdAADADIAQgBBAE4AQwBSAE0AMgAwADEANgAuAGQAZQB2AC4AYwBoAHIAbABhAGIALgBpdddddddddddddddbABhAGIALgBpAG4AdAAHAAgAoBg7uZi80gEGAAQAAgAAAAgAMAAwAAAAAAAAAAEAAAAAIAAAccTLbO5YZuNnhdCDsjPCg1YXJuNv0XuASIhHrWWBg7kKABAAAAAAAAAAAAAAAAAAAAAAAAkAPABIAFQAVABQAC8AYgBhAG4AYwByAG0AMgAwADEANgAuAGQAZQB2AC4AYwBoAHIAbABhAGIALgBpAG4AdAAAAAAAAAAAAAAAAACtRrU1oDZ/XXRVVEUuj0yT
Cache-Control:max-age=0
Cookie:ReqClientId=42484e9a-f488-41a9-a016-1cd6e5820b3c
Host:myhost....
Proxy-Connection:keep-alive
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Mobile Safari/537.36
First, login into CRM and leave the tab sitting there.
Go into POSTMan
Enable the Interceptor (see image)
Enter the URL and hit SEND, just like that. POSTMan will take care of cookies and headers on its own, and you'll see the results.
If you logout from CRM, POSTMan will obviously no longer be able to issue the requests and will return 401 instead.
It seems like the server you are calling requires RFC 4559 (https://www.rfc-editor.org/rfc/rfc4559) authentication. More details here: https://en.wikipedia.org/wiki/SPNEGO.
The way it works in the case of a GET request from the browser:
Browser requests the required page
The server responds with HTTP 401 (Unauthorized) and provides a response header WWW-Authenticate: Negotiate. This tell the browser that RFC 4559 authentication is required.
The browser makes sure the site has permissions for this action (details on configuration here: https://ping.force.com/Support/PingFederate/Integrations/How-to-configure-supported-browsers-for-Kerberos-NTLM). Most sites will not be allowed to request such authorization without being explicitly white-listed.
If permitted, the browser requests a Kerboros ticket from the domain's Active Directory.
Active Directory responds with a ticket.
The browser forward the ticker to the server (via the Authotizarion: Negotiate xxxxx header that you see).
The server interacts with the same Active Directory and turns that ticket into username and groups/permissions information.
I am not aware of a tool that will let you do this (simulate a browser) if you are trying to automate requests against the server (which is probably an internal/intranet company site). Your best course of action may be some form of scripting (like VBS) which will use IE via COM and possibly handle this authentication for you (I have not done this, so not sure if it will indeed work).
You are trying to access from the postman chrome extension or through the postman( windows based) installed application on your system.Try to fetch the data from chrome extension.
I used the following steps and it was ok. Follow the steps, below:
Open Google Chrome
Install Postman Extention
Install Postman's Interceptor Extention
Open Postman Extention
Use Sync
Use Interceptor
In my case in .NET project i had two different authentication schemes in my Startup.cs . I removed the older one and added its auth services and it worked.
Try putting quotes around your url:
curl '[org]/api/data/v8.1/accounts?$select=name,accountid&$top=3'
The &, $, = etc. may be causing problems - I had the same problem and putting quotes was the resolution
These helped me.
Check that it is NTLM authentication both in postman and in the page hosted it is checked.
Use method post
Username and password(which you have set and need not be the access key)
This solved my issue.
In Postman, I copied the Access Token from Authorization tab and I have selected "No Auth" Type.
Then, I moved to Headers tab, Under Headers section, I have provided new Key with Name "Authorization" and in the Value I have passed my TOKEN prefix with Bearer.See the below screenshot
If request works from the browser, then no authentication was used.
So, in Postman, for Authentication, use No Auth. :-)

Testing Web API functionality with Fiddler

I am developing a c# web api application. I am trying to test the /Token (login) and the ChangePassword action. I was able to simulate the /Token request and get the access_token from the response. However, I am unsure of how to use fiddler to test the ChangePassword action. If I just pass the OldPassword, NewPassword and ConfirmPassword, I get an unauthorized error, which makes sense as I have AuthorizeAttribute set as a GlobalFilter. It seems like I have to somehow pass the access_token as well. My question is how do I pass the access_token with the other fields?
I've never used Fiddler for that, but if it's a restful service I would just use Postman (free Chrome extension) or a similar restful client. In Postman you just fill out the URL, click the Headers button and fill out 2 form fields (header/value) to add the access_token to the request.
Good luck

Where does a OAuth 2.0 Redirect URL come from?

I am currently trying to use the LinkedIn REST API. I am using C# and I have been having trouble with OAuth. I have looked at various posts such as this: OAuth with Verification in .NET, which really explained most of the confusing topics, but I am stuck on something that is apparently too obvious to mention: where does the Redirect URL come from? Is this something that LinkedIn should supply? Or is there some format I need to follow for a valid URI? I feel like I must be missing something very obvious or that I must really not understand this stuff at all. Any help would be appreciated!
James
1)Why you need this : Server returns Outh token that is embedded in redirect url, you just need to get that code out of the redirect url and use it for permitted actions(post,editing,tweet etc).
2) How to put this: you will give Redirect url in App Settings or pass it while making request.
For example for facebook:
This will be initial link you will create ,one of its parameter is redirect_uri
https://www.facebook.com/login.php?login_attempt=1&next=https%3A%2F%2Fwww.facebook.com%2Fv2.1%2Fdialog%2Foauth%3Fredirect_uri%3Dhttp%253A%252F%252Fsample.tumblr.com%252F%26display%3Dpopup%26response_type%3Dcode%26client_id%3D549177888517555%26ret%3Dlogin&popup=1
It will be there in Last Successful Response from the server in location header. if you are using webbrowser,it will automatically redirect to the url.
The redirect URL comes from you, you need to create an endpoint on your webapp e.g. http://mysite/api/callback.
Once the request has been authenticated, the token issuance endpoint goes to redirect uri along with token information
under redirect uri, you can extract the code/token information for further use and redirect to the original url.

Categories

Resources