Is there any way to pass a custom parameter to Foursquare that it will pass back in it's response?
In Facebook you can pass custom parameters using the state parameter:
https://www.facebook.com/dialog/oauth?
client_id=YOUR_APP_ID
&redirect_uri=YOUR_REDIRECT_URI
&scope=COMMA_SEPARATED_LIST_OF_PERMISSION_NAMES
&state=SOME_ARBITRARY_BUT_UNIQUE_STRING
The state parameter should be set to some arbitrary string you generate uniquely for each authentication request. This value will be passed back as a parameter to your redirect_uri once the user has authorized your app and you should check that the returned value matched the value you passed in at the start of the flow. This guards against Cross-site Request Forgery by ensuring the incoming redirect is part of the authentication flow which you initiated.
Google also has the state parameter:
state
any string
Indicates any state which may be useful to your application upon receipt of the response. The Google Authorization Server roundtrips this parameter, so your application receives the same value it sent. Possible uses include redirecting the user to the correct resource in your site, nonces, and cross-site-request-forgery mitigations.
It would be extremely helpful to have this using Foursquare as well.
You can specify additional URL parameters in your redirect_uri that are not part of the registered callback URL and they will be passed through upon successful authorization.
Related
My goal is to tell if a user is authenticated, and get their name and email. So far, I can only do the first.
My server app is a NodeJS/Express router. The OIDC server is provided by my company, I believe is compliant, but not under my control. I can do an "Authorization code flow": response_type="code". My Node app eventually responds to the callback route and I can get the "code" and "grant_id" query string values. Other than knowing they exist and presuming that means the user is authorized, I have no idea what I can do with those values. It appears that the only scope that works is "openid".
If I can get the access_code, I can call the UserInfo service and get these values.
My other choice is to do an implicit call. Unfortuantely, the OIDC service it provides the "access_code" and other values after a hash mark on the callback. I believe the flow to be like this:
User makes call to Node app. Detects a lack of authentication, issues redirect to SSO service implicit authorization
User's browser follows redirect to SSO service implicit authorization. User fills it out and is successfully authenticated.
W3 returns a redirect to the provided callback URL.
User needs to cooperate with the app, somehow parse the query string parameters to get the access token and pass this back to the Node application.
The browser calls the provided Node callback application, but without the necessary access token.
I think I could make a proxy server to force OIDC to give my node server the request, just so I can get the access_token. It seems like a very convoluted way to do this, so I have to think there's some simpler way.
Again, all I want is to know the user is authorized to use the app, and what their name and email is. It should not be this hard.
You can use the ID-token to get the details about the user.
It is also important that your identity provider is all about authentication. Final authorization checks should be done in the client, by examining the scopes/claims in the token.
I'm working on authentication part with Google OAuth2 API.
I'm using "server" flow, not "implicit".
When implementing step 1 for obtaining code guidelines recommend using the state parameter to ensure that in the end, the service provider will receive the response that correlates to the auth request he initiated.
See https://developers.google.com/identity/protocols/OpenIDConnect#createxsrftoken
I understand that there is a possibility that code can be stolen, and redirect_uri guessed.
But I don't understand why this is called anti-CSRF protection?
According to wiki CSRF attack "exploits the trust that a site has in a user's browser".
As I understand something sensitive should be kept in the browser to make CSRF attack possible. The most classic example - an authentication cookie.
But what is kept in the browser in relation to OpenID-connect code flow?
It is just two consequent redirects from service provider to identity provider and back. The code itself is passed on callback as a URL param.Browser's role is passive - to be redirected two times. Nothing is stored here.
So my question is what exactly kind of CSRF attack does state prevent? Can anyone give a detailed example? Or is it just misusing of term "CSRF" in google guidelines?
When using the authorization code flow in OAuth2, the user browses to the client application, which then redirects the browser to the authorization server to be logged in and get an access token.
302 https://auth.server/authorize?response_type=code&client_id=....
After you've signed in on the authorization server, it will redirect you back to the registered redirection URI with the issued code. The client application will then exchange the code for an access token and optionally go to a URL encoded in the state parameter.
Now, an attacker could trick you into clicking a link (from an email or something) like:
<a href="https://auth.server/authorize?response_type=code&client_id=...."
This would execute the same request to the authorization server. Once you logged in and the authorization server redirects you back to the client application, the client application has no way of knowing whether the incoming GET request with the authorization code was caused by a 302 redirect it initiated or by you clicking that hyperlink in the malicious email.
The client application can prevent this by sticking some entropy in the state parameter of the authorization request. Since the state parameter will be included as a query parameter on the final redirect back to the client application, the client application can check if the entropy matches what it kept locally (or in a secure HTTP only cookie) and know for sure that it initiated the authorization request, since there's no way an attacker can craft a URL with entropy in the state parameter that will match something the client application keeps.
The objective of CSRF is to dupe the user into performing an action (usually a destructive write action that the user wouldn't do under normal circumstances) in a website by clicking on a link sent by the attacker. An example of such an activity could be deletion of user's own account in the website. Assuming that the user is logged into the website, the requests originating from the user's browser are trusted by the website server which has no way to find out (without the CSRF token) that the user is actually duped into making that request.
In case of Google OAuth2 (Authorization code grant type), note that the initial request to the Google auth server contains the url that the user actually wants to visit after succesful authentication. An attacker can carefully contruct that url with some malicious intent and make the user use it.
The state token check enables the server ensure that the request is indeed originated from its own website and not from any other place. If the attacker creates the url with some random state token, the server wouldn't recognise that and reject the request.
If you have such doubts, best resource you must refer is the specification. For OAuth 2.0, this is RFC6749 . There is a dedicated section in the specification which discuss about Cross-Site Request Forgery
Cross-site request forgery (CSRF) is an exploit in which an attacker
causes the user-agent of a victim end-user to follow a malicious URI
(e.g., provided to the user-agent as a misleading link, image, or
redirection) to a trusting server (usually established via the
presence of a valid session cookie).
From the specification perspective, you must implement state handling mechanism into your application
The client MUST implement CSRF protection for its redirection URI.
This is typically accomplished by requiring any request sent to the
redirection URI endpoint to include a value that binds the request to
the user-agent's authenticated state (e.g., a hash of the session
cookie used to authenticate the user-agent). The client SHOULD
utilize the "state" request parameter to deliver this value to the
authorization server when making an authorization request.
And about a detailed explanation, directly from specifaciton
A CSRF attack against the client's redirection URI allows an attacker
to inject its own authorization code or access token, which can
result in the client using an access token associated with the
attacker's protected resources rather than the victim's
Injecting an authorisation code from attacker, then manipulating your application to behave in a manner attacker wants.
I am trying to integrate Docusign into one of our systems and am trying to do an OAuth integration by using the process that calls out to the DocuSign system and the user gives consent to allow our system to send on their behalf.
I am trying to configure my API Integrator key's callback / redirect URI. I need to pass a value to DocuSign and have that value returned. That value needs to be unique for each request. The best I can tell, when I add a Redirect URI to my APO Integrator Key, that URI can't contain any dynamic values.
For example, my URI is currently set as follows:
http://localhost/mysystem/pages/DocuSignAuth.aspx
When the user sees the DocuSign page, all is good. However, I need to pass a value on that URL, so in reality, my callback URL is:
http://localhost/mysystem/pages/DocuSignAuth.aspx?Id=SomeUniqueValue
Since the return URL no longer exactly matches the Redirect URI defined in my API Integrator Key, the user can't accept/decline.
Is there a way to put a dynamic value on that URL and have it returned when the user accepts?
I think you are implementing Authentication Code Grant, so you can send dynamic value in state parameter Using State Parameter, whatever value you will set in state parameter, same value will be returned by DocuSign once flow is redirected back to Redirect Callback URI. And yes you are correct that RedirectUri should exactly match with the one sent at the time of Authentication Code Grant.
You can use a cookie from your server to hold the dynamic information.
When the browser is redirected to your server after OAuth is complete, the browser will include the cookie it received previously.
Many software webstacks will automatically maintain the cookie and related state for you a session for your app.
If you do manage the cookie via your app, you should encrypt it to guard against a bad guy manipulating the cookie's value.
Why does the redirect URL have to match completely? Wouldn't matching at the domain level be sufficient enough for proper security?
What if I had hundreds of paths?
example urls:
https://myawesomesite.com
https://myawesomesite.com/account/profile
https://myawesomesite.com/games/fungame/points
https://www.myawesomesite.com/games/fungame/points
...
I would have to enter the 4 above redirect urls into my B2C app configuration.
It is common (and easiest) for all authentication requests to contain two redirect URLs:
One (often known as the reply URL) that is passed in the "redirect_uri" parameter, which must be registered with Azure AD B2C, to which all authentication responses are returned from Azure AD B2C to the relying party application. An example of this is https://www.myawesomesite.com/oidc-signin.
Another (often known as the return URL) that is round-tripped in the "state" parameter, which doesn't have to be registered with Azure AD B2C, to which the end user is returned after the relying party application has handled the authentication response. An example of this is https://www.myawesomesite.com/games/fungame/points.
An authentication handler, such as the ASP.NET Core authentication middleware, manages these redirect URLs for you.
For instance, when the authentication handler creates the authentication request, it encodes the currently protected URL (e.g. https://www.myawesomesite.com/games/fungame/points) in the "state" request parameter.
To ensure this URL isn't tampered with, the "state" parameter should be protected, using encryption or signing.
When the authentication handler processes the authentication response, assuming it is a successful response, it creates an identity cookie and redirects the end user from https://www.myawesomesite.com/oidc-signin to the originally protected URL in the "state" response parameter.
This is actually discussed in RFC 6819 "OAuth 2.0 Threat Model and Security Considerations" sections 4.1.5, 4.2.4 and 5.2.3.5.
4.1.5. Threat: Open Redirectors on Client
An open redirector is an endpoint using a parameter to automatically
redirect a user agent to the location specified by the parameter value
without any validation. If the authorization server allows the client
to register only part of the redirect URI, an attacker can use an open
redirector operated by the client to construct a redirect URI that
will pass the authorization server validation but will send the
authorization "code" or access token to an endpoint under the control
of the attacker.
Impact: An attacker could gain access to authorization "codes" or access tokens.
Countermeasures:
o Require clients to register full redirect URI (Section 5.2.3.5)."
Section 5.2.3.5 talks about the cases where this may be too restrictive and purposes alternate solutions.
Often times, the state parameter can also be used to redirect deterministically as suggested by Chris. However, you have to ensure that such a solution also does not end up being an open redirector, so the state parameter will either need to be protected (e.g. encrypted/signed), or used in conjunction with cookies.
I am setting up a single sign on SAML service with zendesk. I am writing a custom SAML server using node/express and using node-samlp.
Zendesk is the SP,
My SAML server has its own IdP
The user steps are as follows:
Navigates to account.zendesk.com and gets redirected to account.com/login?SAMLRequest=asdfasdfafsd
User then enters credentials and posts to the node server.
At the server I am able to parse* the SAMLRequest, verify the user and give the user a SAMLResponse.
The user receives from the node server a SAMLResponse and is redirected to: account.zendesk.com?SAMLResponse=asdfasdf&RelayState=xxx
At that point the user gets a page not found. I am not sure what I'm doing wrong, at this point I'm guessing that my SAMLResponse is either badly formatted or I am redirecting the user to the wrong address.
PS: initially samlp didn't work right out of the box, I forked the repo and updated a couple dependencies and it started to work.
*I was unable to parse the SAMLRequest from zendesk initially. When I used decodeURIComponent on the query param, there were new line characters and white spaces which I replaced with a '+' which made it work. Then I realized that their query param seems to not be URI encoded...
For one thing there is no such thing as a SAML Redirect Binding for the SAML Response. You can send the SAML Response as a form-encoded parameter in an HTTP POST, but you cannot pass it as a query parameter in a redirect. Your SAML IDP implementation is not spec-compliant and Zendesk may be rejecting the message because of that.
See http://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf#page=16 :
Identity Provider issues to Service Provider In step 5, the identity provider issues a message to be delivered by
the user agent to the service provider. Either the HTTP POST, or HTTP
Artifact binding can be used to transfer the message to the service
provider through the user agent. The message may indicate an error, or
will include (at least) an authentication assertion. The HTTP Redirect
binding MUST NOT be used, as the response will typically exceed the
URL length permitted by most user agents.
Indeed, as #hans-z already mentioned, a SAMLResponse is always sent over POST! You can trigger this browser POST by serving a page that automatically submits a form (containing the SAMLResponse) on page load (through JavaScript).
Since you're sending over POST, your SAMLResponse should not be URL encoded anymore.