I am looking at the best way to implement POST redirect. Consider this example:
Customer receives the URL: https://domain-a.com
When customer clicks on this URL, we need to redirect the customer to https://domain-b.com
The redirect needs to be over HTTPS POST. In this redirect, some parameters would also be sent.
I searched around for the best way to implement it so that it works for both JS enabled & disabled browsers.
HTTP protocol doesn't support POST redirect. I read about new HTTP status code 307 that can be used for redirect. However, it will not work for us. It says that redirect should happen in the same way as original request. In this case, original request is GET.
The method which I am thinking is this:
domain-a returns an HTML form with all the parameters. The form is present in noscript tag.
Javascript is executed on body load to automatically submit the form to domain-b. I don't want to show the experience of "Submit" button to customer for which they don't need to take any action. It should look more like a normal redirect to them.
JS disabled browser will see the form and they would need to manually click it.
I am looking for feedback on any potential issues with this approach or better way to handle this case.
I am using 'omniauth-linkedin-oauth2'.
When I am login with linkedin then I am getting this error
Invalid redirect_uri. This value must match a URL registered with the API Key.
This is my settings:
Went back to LinkedIn developer site (https://www.linkedin.com/secure/developer ) to check my setting again. Everything matches API Key, Secret Key and OAuth 2.0 Redirect URLs.
Searched web looking for some clues. Couldn’t find a one. Crazy issue:
Then I saw that in the URL Owin was appending some extra string to the redirect_uri “signin-linkedin”. When I decoded the URL I saw this http://localhost:54307/signin-linkedin . I took this URL and placed it in the OAuth 2.0 Redirect URLs field in the LinkedIn developer site.
This link is helpful for me
https://naveengopisetty.wordpress.com/2014/09/15/linkedin-oauth-2-0-issue-invalid-redirect_uri-this-value-must-match-a-url-registered-with-the-api-key/
You can just look in url that you are getting that error message on.
eg. if you are using python's social auth the url would look like this:
https://www.linkedin.com/uas/oauth2/authorization?scope=r_basicprofile+r_emailaddress&state=XXXXXX&redirect_uri=http://example.com.au/sa/complete/linkedin-oauth2/&response_type=code&client_id=YYYYYYY
so you would use this part of the above url for the redirect url
http://example.com/sa/complete/linkedin-oauth2/
please check your redirect_url. for my case I see like this.
https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=77k93y0w31zaey&redirect_uri=http%3A%2F%2Flocalhost%3A1729%2Fsignin-linkedin&scope=r_basicprofile%2Cr_emailaddress&state=nhAC-nR-CgEwO3XS2ezANhuPBMz-IUmLPJYgGHlZvZ8B1pCfsGBU0PR0dZ5XxE4zbyeI0RLcKByqPLKkgQdqMm4s6DjFYqMCEehYA2iWT9MfioEHjPXGCt2USxUTF0wKBpflCUjG5URVlJa3qI7U3ydFOErZ4Hhnr9SVmKdf1bithYfbOqBx345o8LQLexbddQ687vP6y0szrIyCM6FHip1tCpOY3Hgg5FJQEFH1mCJ_yLunD5vDUN4VVfkQbcjk
for this I add the url for OAuth 2.0 Authorized Redirect URLs:
http://localhost:1729/signin-linkedin
where http://localhost:1729 =base url and
signin-linkedin = the string which add after base url
One more solution is to just verify the client_id you've been using the whole time..because with every update in the list of redirect_uri, the client_id gets updated.
Worth mentioning when one uses libraries to handle oauth: some libraries fail to care about the protocol that is used (or at least require further parametrization). Eg, I gave Linkedin https://example/callback as oauth2 url, but the library sent the request with http://example/callback as parameter.
I had this when trying to authorise from a zurb Reveal modal popup. In my case, the issue was the URL for the page that was being displayed in the popup was not in my OAuth2 Redirect URLs list on the LinkedIn developer site.
That was easy to miss because the page URL from the page in the modal is not the URL that was currently showing in the browser's address bar. Once I added the URL for the page being shown in the pop up it worked.
After spending hours i finally get to the solution. You got an error no issues just check the url and find redirect_uri. Copy and Paste it's value it in your linkedin dev account oauth2 redirect field.
Make sure to add both with and without trailing '/' as redirect url.
http://localhost:8000/oauth/complete/linkedin-oauth2
http://localhost:8000/oauth/complete/linkedin-oauth2/
I have requirement is like below.
The user can call the url like domainname/applicationname/instancesname
For Ex: abc.com/xyz/pqr
From the URL with instance name I need to take and i need to redirect to the login page.
but what ever the user is enter the URL, I should keep in browser url.
[Because user may bookmark the URL]
Think I will receive the instance name dynamically.
how can i use this in Spring MVC.
The main concept is single url we are handling with multiple instances.
Unless you don not pass any url parameters with abc.com/xyz/pq this url it wont be a problem. Book mark url will work since you have the request mapping in your controller.
This question is a question about login flows for web-apps in general. I'm most interested in answers that optimize for usability and performance while maintaining security.
What is the most appropriate way to handle unauthenticated requests to bookmarked URLs?
To demonstrate the problem, here are some routes and respective behaviors for an example application:
GET /login -> Display the authentication form
POST /processLogin -> process the username and password,
if unauthentic...re-render the login form;
otherwise...display the default page
GET /secret -> if authenticated...display the secret resource;
otherwise...display a login form
POST /secret -> if authenticated...perform a desirable, but potentially
non-idempotent action on the secret
resource
otherwise...display a login form
Option 1: Display login screen, redirect to desired page
User clicks bookmark
GET /secret -> 200, surreptitiously display login form with hidden field path="/secret"
POST /processLogin -> 302 to /secret (value of path parameter)
GET /secret -> 200, secret resource displayed
Analysis: Hopefully, your client is a modern browser, non-compliant with HTTP, such that it performs a GET after a 302'd POST. This applies across the board. Should I be worried?
Option 2: Redirect to login screen, redirect to desired page
User clicks bookmark
GET /secret -> 302 to /login
GET /login via redirect -> 200, login form displayed with hidden field path="/secret"
POST /processLogin -> 302 to /secret
GET /secret -> 200, secret resource displayed
Analysis: Same problems as above. Added problem that the URL displayed by the browser during login changes, which is confusing to the user and breaks bookmarking, link sharing, etc.
Option 3: Display login screen, display desired page
User clicks bookmark
GET /secret -> 200, surreptitiously display login form with action="/secret"
POST /secret -> 200, secret resource displayed
Analysis: Sadly, the refresh button is now also broken: refresh will cause the user agent to re-POST with a warning, instead of re-GETing /secret. They user gets a warning, but if they ignore it, something bad happens.
On the bright side, you minimize roundtrips with this technique.
Option 4: Redirect to login screen, display desired page
User clicks bookmark
GET /secret -> 302 to /processLogin
GET /processLogin via redirect -> 200, login form displayed with action="/secret"
POST /secret -> 302 to /secret
GET /secret -> 200, secret resource displayed
Analysis: Same problems as options 2+4.
Option 5: ???
Is there another technique I'm missing?
In general, which of these techniques would you recommend?
See Also
What is correct HTTP status code when redirecting to a login page?
What kind of HTTP redirect for logins?
HTTP response with redirect, but without roundtrip?
Option 1 & 3 are not following the HTTP RFC as "surreptitiously display login form" contradicts 200 GET response, where "an entity corresponding to the requested resource is sent in the response" is expected.
Option 2 is OK. All modern browsers support 302 on POST and many REST-based frameworks (like RoR) actively use it. Alternatively in "302 to /login" you can already create the session (cookie) and store the URL in session, to avoid passing the original URL in GET parameters. From usability standpoint, you can have an appropriate message on login page too (I think the URL mismatch is irrelevant here - you can't let the user see the content anyway).
Option 4: when you POST to /secret, HTTP RFC expects you to "accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line", but all you are doing is logging in and not creating anything new under /secret.
So following HTTP RFC, your best choice is Option 2. Actually Option 2 is also in line with POST->Redirect->GET design pattern, which helps to address the issue of unpredictability in bookmarking URLs to POST'ed resources.
My $.02: I recently implemented using option 2 (although I stored /secret in a session, not in the login form as a hidden field).
I don't entirely share your concerns:
Added problem that the URL displayed
by the browser during login changes, which is confusing to the user
and breaks bookmarking, link sharing, etc.
Redirecting to /login, and the subsequent change of URL, tells the user that before they can continue there's something else that needs to be done first: logging in.
Since a login page will look entirely different from the 'target page', I don't see how that will confuse people into bookmarking and/or link sharing the login page instead of the target page (since the login page won't contain the information they want to bookmark/share anyway).
And if you're worried about 302's breaking the standard (although every single browser I know will happily break it), consider using 303's instead.
Note that mickeyreiss is correct, using AJAX Option 3 works without the drawback of the broken back button. However, it means the user has to have JavaScript enabled. This being said, if you program your form properly, you can detect whether JS is present, if not use Option 1.
Note that the 302 response is fine, however, you may have problems with caches. You have to make sure that nothing gets cached if you want to show 2 completely different pages/forms on for the same URI. (/secret showing the login and then the actual secret.)
I almost always use option #2, simply because the content returned by a URL is consistent. While today's secrets are hidden behind a login, tomorrow you may want to open it up or display mixed public/secret depending on authentication at the same URL. In that case, option #2 will be most like what Google would expect. Any content bait and switch is looked down on by Google and in the extreme case, all of your pages would have duplicate page content (ie. login form).
I would choose the option using AJAX:
login page and hide the content
the user enters the login and the password.
Authentication is done in the server side.
The server returns a result
if successful use location.href to set the page you would like to
go to, or else you can output a message saying the login is not
valid.
In your server you will be testing on a _SESSION variable, if not set redirect to the login page..
I've a registration system which redirects user to specific page lets say success.php
In this page I've custom script that sends out Welcome mail to the user and posts success on facebook since registration is through FB oath.
I would like to redirect success.php to the original page user was reading before asking for registration/login.
How do I do this?
I'm using Wordpress as CMS if its helpful.
Would something like this work in all situations?
$_SERVER['HTTP_REFERER']
There are many ways to redirect users in Wp the simplest one being :
wp_redirect() (HERE) which has 2 parameters :
$location = The absolute URI to which the user will be redirected. No default.
$status = The status code to use. For example, 301, 302, etc. The default is 302.
wp_redirect('http://mywebsite.com/',302);
Note that it is also pluggable.
Then you have
auth_redirect();
which is basically the same but requires login before giving access - no parameters
you also have a login_redirect filter which you can use ,but i am not sure it is for your case as described.