Home > OS >  "detail": "CSRF Failed: CCSRF token missing." when sending post data from angula
"detail": "CSRF Failed: CCSRF token missing." when sending post data from angula

Time:11-28

i need to send the post data from angular to DRF through angular form but geeting the error

i checked almost all the answers available on the internet but did not found and useful answer.

 "detail": "CSRF Failed: CSRF token missing."

//post logic sources.service.ts

import { Injectable } from '@angular/core';
import { sources } from './sources';
import { HttpClient } from '@angular/common/http';
import { Observable , of, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
import { HttpHeaders } from '@angular/common/http';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type':  'application/json',
//     Authorization: 'my-auth-token',
    cookieName: 'csrftoken',
    headerName:  'X-CSRFToken',
//     X-CSRFToken: 'sjd8q2x8hgjkvs1GJcOOcgnVGEkdP8f02shB',
//     headerName: 'X-CSRFToken',
//      headerName: ,
  })
};

@Injectable({
  providedIn: 'root'
})
export class SourcesService {
API_URL = 'http://127.0.0.1:8000/sourceapi.api';
  constructor(private http: HttpClient) { }

     /** GET sources from the server */
    Sources() :  Observable<sources[]> {
      return this.http.get<sources[]>(this.API_URL);
    }
      /** POST: add a new source to the server */
//       addSource(data: object) : Observable<object>{
//         return this.http.post<object>(this.API_URL,data, httpOptions);
//       }

addSource(source : sources[]): Observable<sources[]>{
  return this.http.post<sources[]> (this.API_URL, source, httpOptions);
 //console.log(user);
  }
  }


//add-source.component.ts

import { Component, OnInit } from '@angular/core';
import { sources } from '../sources';
import { SourcesService } from '../sources.service';
import { FormGroup, FormControl, ReactiveFormsModule} from '@angular/forms';

@Component({
  selector: 'app-add-source',
  templateUrl: './add-source.component.html',
  styleUrls: ['./add-source.component.css']
})
export class AddSourceComponent implements OnInit {
   // a form for entering and validating data
   sourceForm = new FormGroup({
    name : new FormControl(),
    url : new FormControl(),
    client : new FormControl(),
  });
  constructor(private sourcesService: SourcesService) { }

  ngOnInit(): void {
  }

  sourceData_post: any;
  saveSource(){
    if(this.validate_form()){
      this.sourceData_post = this.sourceForm.value;
      this.sourcesService.addSource(this.sourceData_post).subscribe((source)=>{
      alert('source added');
      });
      }

      else{
      alert('please fill from correctly');
      }
  }
  validate_form(){
    const formData = this.sourceForm.value;
    if(formData.name == null){
      return false;
      }else if(formData.url == null){
      return false;
      }else{
      return true;
      }
      }

}

// add-source.component.html


<div >
    <div>    <span>Add Source</span>   </div>
</div>
<div >
        <div >
            <form action="" [formGroup]="sourceForm" (ngSubmit)="saveSource()">

                <table>
                    <tr>
                        <td>Source Name:</td>
                        <td>
                            <input  type="text" formControlName="name">
                        </td>
                    </tr>
                    <tr>
                        <td>Source URL:</td>
                        <td>
                            <input  type="text" formControlName="url">
                        </td>
                    </tr>

                     <tr>
                        <td>Source client:</td>
                        <td>
                            <input  type="text" formControlName="client">
                        </td>
                    </tr>
                    <tr>
                        <td colspan="2">
                            <div >
                                <button type="submit">submit</button>
                            </div>
                        </td>
                    </tr>
                </table>
            </form>
        </div>
</div>

i tried

imports: [
  BrowserModule,
  AppRoutingModule,
  HttpClientModule,
  Ng2SearchPipeModule,
  FormsModule,
  ReactiveFormsModule,
  HttpClientXsrfModule,
  HttpClientXsrfModule.withOptions({
    cookieName: 'XSRF-TOKEN',
    headerName: 'X-XSRF-TOKEN',
    })

but did not help

Note :- this is angular 13

CodePudding user response:

you need to exempt csrf in views.py

from django.views.decorators.csrf import csrf_exempt

and then

@csrf_exempt
def index(request):
pass

CodePudding user response:

(Partial answer)

You get this error message because the CSRF protection is activated by default and you don't send the CSRF token. Someone wrote a good description of what CSRF is here

On the first GET request, the server sends you the CSRF token in a cookie, and you have to send it back on every request, as a cookie AND as a request header. The server will check that the CSRF value in the cookie matches with the CSRF value that is in the header.

It can be tedious to repeat that on every request so Angular has a builtin module for that : HttpClientXsrfModule that you configured here :

HttpClientXsrfModule.withOptions({
  cookieName: 'XSRF-TOKEN',
  headerName: 'X-XSRF-TOKEN',
})

One problem is that you override this behavior by setting again the header by hand here :

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type':  'application/json',
    cookieName: 'csrftoken',
    headerName:  'X-CSRFToken',
  })
};
[...]

addSource(source : sources[]): Observable<sources[]>{
  return this.http.post<sources[]> (this.API_URL, source, httpOptions);

You don't need that. Just leave it like this :

addSource(source : sources[]): Observable<sources[]>{
  return this.http.post<sources[]> (this.API_URL, source);

Another problem is that the name for the CSRF header/cookie is not standard. It can be CSRF, XSRF, or whatever you want. Of course, if you send it as CSRF and the server expects it as XSRF, it will not be detected.

As I can see from the comments on the question, the server sends you that

Set-Cookie: csrftoken=sjd8q2xsdfgfhjgfnVGEkdP8f02shB

So we are sure that the cookie name is csrftoken. So it should be the same in the configuration of the HttpClientXsrfModule. Can you try like this

HttpClientXsrfModule.withOptions({
  cookieName: 'csrftoken', // << This one is certain
  headerName: 'X-XSRF-TOKEN', // << For this one, I don't know yet
})

Can you try this with different values for the headerName ? Preferably csrftoken also ? header name and cookie name are often the same.

Update :

According to the Django documentation, the default CSRF header name is HTTP_X_CSRFTOKEN. So you can try this :

HttpClientXsrfModule.withOptions({
  cookieName: 'csrftoken',
  headerName: 'HTTP_X_CSRFTOKEN',
})
  • Related