Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular is ignoring withcredentials #15805

Closed
chaouiy opened this issue Apr 6, 2017 · 47 comments
Closed

Angular is ignoring withcredentials #15805

chaouiy opened this issue Apr 6, 2017 · 47 comments

Comments

@chaouiy
Copy link

chaouiy commented Apr 6, 2017

I have more 3 days working to figure out why browser can't recieve cookies until I have found that Angular 2 is ignoring withCredentials:true. please fix it. this will save the life of many developers

@tytskyi
Copy link

tytskyi commented Apr 6, 2017

@chaouiy
Copy link
Author

chaouiy commented Apr 7, 2017

does it change something the fact to send pure javascript object or RequestOptionsArgs ?

@tbosch
Copy link
Contributor

tbosch commented Apr 8, 2017

No, RequestOptionsArgs is just an interface, i.e. values are always just pure javascript objects.

Closing as not a bug nor feature.

@chaouiy
Copy link
Author

chaouiy commented Apr 9, 2017

I am still stuck with the issue, with credentials is ignored I use Angular 4.x. I don't recieve cookies

@tbosch tbosch reopened this Apr 10, 2017
@alxhub
Copy link
Member

alxhub commented Apr 10, 2017

@amineparis can you show the code you use to create the request with withCredentials set to true? In my testing, it works.

@chaouiy
Copy link
Author

chaouiy commented Apr 12, 2017

@alxhub Here it is. I am depressed because of it :( +7 days full time trying to figure it out

login(username : string, password : string) {
    let data = {username: username, password: password}
    let optionsArgs:RequestOptionsArgs = { withCredentials: true }
    let options = new RequestOptions(optionsArgs)
    return this.http.post(environment.apiEndpoint + 'login', data, options)
      .catch((error) => {
        return Observable.throw(error.json());
      });
  }

@chaouiy
Copy link
Author

chaouiy commented Apr 19, 2017

any heeeeeeeeelp +15 days full time working to figure it out, I am gonna fucking suicide because of it.

I recieve cookies well when I make manual ajax request with withcredentials:true, that means the problem is not the server is that Angular 2 is not sending this option

@JanStureNielsen
Copy link

@amineparis -- as requested multiple times above, create a small sample demonstrating the problem; if you'd like help/support, submit a question to Stack Overflow, instead.

@chaouiy
Copy link
Author

chaouiy commented Apr 20, 2017

it's Angular 2 problem everything is in place. it's a cross origin request.

@antonyRoberts
Copy link

@amineparis Do you have access to the server code, you're trying to connect to?

@chaouiy
Copy link
Author

chaouiy commented Apr 21, 2017

@antonyRoberts Yes I have. withCredentials are considered and cookies are recieved if I do native Jquery request to the same server. problem occures only when I call using Angular 2. the thing I need to debug the problem is how to know using google chrome for developers if withCredentials is true within a given request, I can't find any header field dedicated to that

@dannyhuly
Copy link

Any updates or good alternatives ideas to support cookie authentication ?

@tytskyi
Copy link

tytskyi commented Jul 20, 2017

@dannyhuly it's already working. Do you set withCredentials to true when make request?

const options = {}
options.withCredentials = true;

this.http.get(url, options)

@dannyhuly
Copy link

Sorry, the withCredentials works as intended. The cookie was set to "secure" and I didn't implement https.

This issue should be closed.

@jesben
Copy link

jesben commented Aug 31, 2017

I'm in an Windows env. with NTLM, I got the same problem with CORS. I resolve it by removing headers from the options, it's feels like when adding headers, withCredentials gets overruled! I'm using http 4.3.1

Gives 401

let body = JSON.stringify(data);
let headers = new Headers({'Content-Type': 'application/json'});
let options = new RequestOptions({headers: headers, withCredentials: true});

Works:

let body = JSON.stringify(data);
let options = new RequestOptions({withCredentials: true});

@atigm
Copy link

atigm commented Oct 4, 2017

I have the same problem, withCredentials: true didn't working !
I use Angular 4.3.4

@trotyl
Copy link
Contributor

trotyl commented Oct 4, 2017

@Abdhafid Then help to provide a reproduction please.

@atigm
Copy link

atigm commented Oct 4, 2017

I upgrading from Angularjs to Angular 4, after authentication, I call WS spring to get a list of objects :

  • angularjs (it's working) : the request header contains a parameter called Cookie, his value include all parameters from Set-Cookie response
  • angular 4 (KO 401) : Cookie parameter not contains Set-Cookie response parameters.

Using or not header/withCredentials, I have always 401 Unauthorized :
Spring exception : org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource

this.headers.append( 'Content-Type', 'application/x-www-form-urlencoded' );
......
return this.http.request( new Request( {
            method: verb,
            url: urlTmp,
            body: body,
            headers: this.headers,
            withCredentials: true
        } ) ).map( response => response.json() );

@trotyl
Copy link
Contributor

trotyl commented Oct 4, 2017

@Abdhafid

you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5

@atigm
Copy link

atigm commented Oct 4, 2017

I Can't reproduce my problem on http://plnkr.co (I must call Spring WS)

@trotyl
Copy link
Contributor

trotyl commented Oct 4, 2017

You can call anything in Plunker within the internet.

And if it's a CORS problem, then nothing should be related to Spring specifically.

Actually from the conversation above it's quite clear they don't have a valid backend configuration, if you can reproduce the same backend, then we can tell you which part you did wrong. (Although that's not something should happen in this channel.)

@atigm
Copy link

atigm commented Oct 5, 2017

I belive the problem it's because I'm using proxy.conf.json

{
    "*": {
        "target": "http://localhost:8080/app",
        "secure": false,
        "logLevel": "debug",
        "changeOrigin": true
    }
}

@breitling
Copy link

withCredentials: true is working for GETs but not for POSTs.

@trotyl
Copy link
Contributor

trotyl commented Oct 24, 2017

withCredentials: true is working for GETs but not for POSTs.

@breitling That's a clear evidence you don't have valid CORS setting, try add custom headers to GET or use application/x-www-form-urlencoded for POST you'll get the opposite.

@chaouiy
Copy link
Author

chaouiy commented Oct 27, 2017

Found the problem finally after 2 weeks of hard work, I was using localhost in front and 127.0.0.1 on back. Google chrome juged that it is not secure to share cookies (it is not the same host). Stupid browser :(

@chaouiy chaouiy closed this as completed Oct 27, 2017
@nithindan
Copy link

@amineparis I have the same issue. How did you solve it ?

@chaouiy
Copy link
Author

chaouiy commented Nov 9, 2017

it's explained on my last comment

@inovozenko
Copy link

@amineparis, thanks a lot for your investigation and conclusion!

@guguji5
Copy link

guguji5 commented Jan 8, 2018

I figure it out with the proxy. I can't call a post request with authorization header.

@otello1971
Copy link

otello1971 commented Jan 11, 2018

  1. Construct a POST request with options which include

        withCredentials: true
    

(keep sending this option back to the server on any following request to keep "alive" your cookie)

  1. In ExpressJS set two necessary CORS options configuration:

        credentials: true,  
        origin: <any other than '*'>
    

Example:
Angular: "Post" Request

  this.http
          .post<HttpResponse<Object>>(
              'http://192.168.188.129:3000/tools/login',
              result,
              {
                observe: 'response',
                headers: new HttpHeaders().set('Content-Type', 'application/json'),
                responseType: 'json',
                withCredentials: true
              }
          )
          .subscribe(
            (resp: HttpResponse<Object>) => {
              console.log('Response: ' + JSON.stringify(resp));
          });

ExpressJS: (with some Cors options):

var cors = require('cors')
var cookieSession = require('cookie-session')
var app = express()

var corsOptions = {  // needed by Angular
  credentials: true,  
  origin: [undefined, 'http://localhost:4200', 'http://localhost', 'http://192.168.1.151', 'http://192.168.1.151:4200']  
}

app.use(cookieSession({
  secret: 'secreto'
}))
app.post('/tools/login', cors(corsOptions), (req, res, next) =>{
    req.session.token = 'hola'
    res.statusCode = 200
    res.setHeader('Content-Type', 'application/json')
    res.json({ status: 'ok', body: 'You are successfully created a cookie!' })
})

@harimada
Copy link

harimada commented Feb 8, 2018

Hi,

I am still facing the issue. I tried like below but no luck.
let options = new RequestOptions({withCredentials: true});
return this.http.post(http://machinename:9091/rest/servicel,framework,{withCredentials: true});

Could you please share your code.

@inovozenko
Copy link

@harimada Hi!

I'm using Angular 4.4.6.

The new way for this Angular:

req = req.clone({
  withCredentials: true
});

AuthInterceptor:

import { Injectable } from '@angular/core';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse, HttpErrorResponse} from '@angular/common/http';
import {Router} from '@angular/router';

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/do';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor(private router: Router) { }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    req = req.clone({
      withCredentials: true
    });

    return next
      .handle(req)
      .do(event => {
        if (event instanceof HttpResponse) {}
      }, (error: any) => {
        if (error instanceof HttpErrorResponse) {
          if (error.status === 401) {
            this.router.navigate(['/login']);
          }
        }
      });
  }
}

AppModule:

import {NgModule} from '@angular/core';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {BrowserModule} from '@angular/platform-browser';
import {JsonpModule} from '@angular/http';
import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';

import {AppComponent} from './app.component';
import {AppRoutingModule} from './app-routing.module';
import {CoreModule} from './core/core.module';
import {AuthInterceptor} from './core/services/auth-interceptor.service';
import {PageNotFoundModule} from './page-not-found/page-not-found.module';

@NgModule({
  imports: [
    BrowserAnimationsModule,
    BrowserModule,
    JsonpModule,
    HttpClientModule,

    CoreModule,
    PageNotFoundModule,
    AppRoutingModule
  ],
  declarations: [
    AppComponent
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
}

@ghost
Copy link

ghost commented Feb 17, 2018

Hi,I have had the same problem.When I use this.http.get(this.accountUrl + 'ExternalLoginConfirmation', { withCredentials: true })
I get the following error :
`Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:4202' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
Odd thing : There isn't any error when I call this url by browser

Could you help me?

@breitling
Copy link

breitling commented Feb 23, 2018 via email

@webmail716
Copy link

^ The most recent question is because the CORS is configured incorrectly. You can't set withCredentials: true AND have origins '*' in your CORS file. You have to be specific about which origins you want to allow credentials from.

@webmail716
Copy link

webmail716 commented Mar 16, 2018

I was able to fix the 401 error code I was receiving from my rails server by adding the following line to my ApiController:

class ApiController < ActionController::Base
// protect_from_forgery with: :null_session --- didnt work
// skip_before_action :verify_authenticity_token --- didnt work

// Taken from http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
protect_from_forgery unless: -> { request.format.json? }
end

@StavM
Copy link

StavM commented Apr 15, 2018

Guys, Notice that if you set a custom Authorization header (interceptor used for JWT for example)
your NTLM windows-authentication requests will get revoked by the server (401).

This is because under the hood, the request your browser sends actually already has a header, that you can not see on chrome developer tools for some reason. with Wire-shark however, you can sniff it:
Authentication: NTLM <token>

the moment you set your own custom header (Authentication: Bearer <my jwt token> notice not Authorization) for example, you're overriding it. hence getting a 401 response to your requests.

@daemonblade
Copy link

daemonblade commented Jun 3, 2018

I'm using Angular 6 with a Spring Framework backend. I use the following options with HttpClient POST to login (successfully):

const httpPostOptions =
{   
    headers:
        new HttpHeaders (
        {   
            "Content-Type": "application/x-www-form-urlencoded"
        }),
    withCredentials: true,
}

All subsequent HttpClient GET work with:

const httpGetOptions =
{   
    withCredentials: true,
};

However, subsequent HttpClient POST fails, even with:

const httpPostOptions =
{   
    headers:
        new HttpHeaders (
        {   
            "Content-Type": "application/json"
        }),
    withCredentials: true,
};

The Spring Framework backend is configured correctly, as the initial POST and subsequent GETs work fine. Only subsequent POST fails. Any pointers appreciated.

@Rhobal
Copy link

Rhobal commented Jun 15, 2018

I'm stuck at the same issue. Angular is running on localhost:4200 and Jersey webservices at localhost:8080.
withCredentials is set to true.

The network panel of Chrome shows that the session cookie is added to the GET request, but when I submit a POST, the panel shows the preflight OPTION requests without cookie, which fail due to the missing cookie.

Any pointers appreciated

@daemonblade
Copy link

@Rhobal I've raised #24283 with a sample test case. Unfortunately it's not getting enough attention. Perhaps you could add your comments there instead?

@harimada
Copy link

harimada commented Jun 16, 2018

@Rhobal. Please check in web.xml if OPTIONS is placed in security constraints. If present remove that and try it will work. I too faced similar issue for post req
http-method OPTIONS

For options request it will not send cookies

@Rhobal
Copy link

Rhobal commented Jun 16, 2018

@harimada thank you! Indeed, OPTIONS requests do not come with cookies as specified. Here is what worked for me:

  • Add a security-constraint without auth-constraint for OPTIONS requests in web.xml:
	<security-constraint>
		<display-name>No check for options</display-name>
		<web-resource-collection>
			<web-resource-name>All Access</web-resource-name>
			<url-pattern>/*</url-pattern>
			<http-method>OPTIONS</http-method>
		</web-resource-collection>
		<user-data-constraint>
			<transport-guarantee>NONE</transport-guarantee>
		</user-data-constraint>
	</security-constraint>
  • Add OPTIONS handling to filters that expect a user to be present
  • Add special pre-flight handling to my CORS filter, based on the RESTeasy CorsFilter as suggested on Stack Overflow

@scottie
Copy link

scottie commented Aug 1, 2018

welcome to angular, i suggest vuejs or reactjs :) Lets face it who the fuck likes typescript anyway....

@BMLande
Copy link

BMLande commented Nov 20, 2018

i am working working angular 6 app , i need sent back cookies on each request for req validation from server side

  • i have done this in angular2,4,5 (here we use "Http" no http client)
   getConference(){ let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers, withCredentials: true });
        return this.http.post(SERVER_API_URL + 'proxta/api/conferences', conferenceData, options);
     }

**NOTICE HERE RequestOption is deprecated in *HTTPCLIENT (angular5 and above)

But when we working with angular6 and above version app you need to use HttpClient (htttp is deprecated here) and there is a big problem how to sent *RequestOption in requst.

I need to say really thanks to this man @inovozenko , best way to this with interceptors .thank u so much u saved myd day.

@siva563
Copy link

siva563 commented Nov 28, 2018

withCredentials: true is working fine in Chrome, but when I am trying in Safari Browser it is not working any solution to solve this issue.

Thanks in advance !!

@Irfan223
Copy link

Irfan223 commented May 7, 2019

I am still stuck with the issue, with credentials is ignored I use Angular 4.x. I don't recieve cookies

I am also facing same problem. How you got cookies?

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 15, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests