Below php api script given by client when I run into local then Static data storing in api server successfully.
<?php
//creating payload parameters:
$classTitle = 'Demo Class on 3rd April, 2020';
$classInfo = 'This is a demo class scheduled to understand API';
$classDateTime = '2020-11-12 11:30 AM';
$timezone = 'Asia/Kolkata';
$classDuration = 15;
$classRecording = 'yes';
$classAutoStart = false;
$recordingAutoStart = false;
$classVideoRes = 720;
/*xyz.com*/
$apiKey = '12345';
$secretKey = '12345';
// Create token header as a JSON string
$header = json_encode(['alg' => 'HS256','typ' => 'JWT']); // ensure to place first alg part and next typ part
// Create token payload as a JSON string
$payload = json_encode(['classTitle' => $classTitle ,'classInfo' => $classInfo ,'classDateTime' => $classDateTime ,'timezone' => $timezone ,'classDuration' => $classDuration ,'classRecording' => $classRecording ,'classAutoStart' => $classAutoStart ,'recordingAutoStart' => $recordingAutoStart ,'classVideoRes' => $classVideoRes ,'apiKey' => $apiKey]);
// Encode Header to Base64Url String
$base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
// Encode Payload to Base64Url String
$base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
// Create Signature Hash
$signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, $secretKey , true);
// Encode Signature to Base64Url String
$base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
// creating JWT token variable
$jwt_token = $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;
// creating authorization varibale
$authorization = 'Bearer '.$jwt_token;
?>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript">
$.ajax
({
type: "POST",
url: 'https://xyz/client/schedule',
contentType: 'application/json',
data: JSON.stringify({
"apiKey": "12345"
}),
dataType : 'json',
headers: {
'authorization': '<?php echo $authorization; ?>'
},
success: function(retval)
{
// alert(retval);
console.log(retval);
// var success = retval.success;
}
});
</script>
Directly i pass parameters to above php api then also its not working, my senior told me you have to call above code from angular I wrote code but i am not able to store successfully below is my angular code.
Below is my model class
export class Schedule1 {
classTitle: string;
classInfo: string;
classDateTime: string;
timezone: string;
classDuration: number;
classRecording:string;
classAutoStart: boolean;
recordingAutoStart: boolean;
classVideoRes: number;
constructor() {
}
}
Below is component.ts on button click passing static values
import { Schedule1 } from '../Models/Schedule1.model'
Schedule1: Schedule1 = new Schedule1();
addSchedule(scheduleForm: NgForm): void {
//static data parameter passing
this.Schedule1.classTitle='hi Class on 3rd April, 2020';
this.Schedule1.classInfo= 'This is a demo class scheduled to understand API';
this.Schedule1.classDateTime= '2020-11-12 11:30 AM';
this.Schedule1.timezone= 'Asia/Kolkata';
this.Schedule1.classDuration= 15;
this.Schedule1.classRecording= 'yes';
this.Schedule1.classAutoStart= false;
this.Schedule1.recordingAutoStart= false;
this.Schedule1.classVideoRes= 720;
//const data = JSON.stringify(this.Schedule1);
const data = {
apiKey: "dcbf187d-bdfe-431b-8f60-fa19bf51cd85",
data: JSON.stringify(this.Schedule1)
}
this.subscription = this.userSvc
.fetchData("https: //xyz.com/client/schedule", data)
.subscribe(
data => {
// Data on Success
console.log("data", data);
},
error => {
console.log("error", error);
}
);
}
Below is service.ts
fetchData(url: string, data: any): Observable<any> {
const headers = {
Authorization: "Bearer "+"1234",
"My-Custom-Header": "foobar",
contentType: "application/json"
};
return this.http.post(url, data, {
headers
});
}
in console getting this error.
Can you please try the following changes in your code to check if it works:
First change:
const data = this.Schedule1;
Second change
fetchData(url: string, data: any): Observable<any> {
const headers = {
Authorization: "Bearer "+"dcbf187d-bdfe-431b-8f60-fa19bf51cd85",
"My-Custom-Header": "foobar",
contentType: "application/json"
};
return this.http.post(url, data, {
headers
});
}
I think you need to define the type of request option that you passing to request so you have to use
return this.http.post(url, data, headers: new HttpHeaders({
'Content-Type': 'application/json',
'My-Custom-Header': 'foobar',
Authorization: 'my-auth-token'
}));`
also, you need to import HttpHeaders
import { HttpHeaders } from '#angular/common/http';
Try using unblock cors extension on your browser and check it again
you are getting this error 'https ://xyz.com/client/schedule' from origin 'localhost:4200' has been blocked by CORS policy because server and client is running on different host, either you have to run server locally or try this,
open chrome using this command and check browser network tab
chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security
Did you try to setup a config file "src/proxy.conf.json"
{
"/api/*": {
"target": "http://localhost:4200",
"secure": false,
"logLevel": "debug"
}
}
and have your "angular.json" point to the config file
"architect": {
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "your-application-name:build",
"proxyConfig": "src/proxy.conf.json"
},
this will only be for testing purposes (since you have no access to the server, right ?)
Related
I am sending the username and password to the PHP api with the API_KEY in the .env file. How do I get the user name before the semicolon as the password after the comma in Api? I could not run it with the current code I wrote. I'm using basic auth
.env
API_KEY=...:...
REACT CODE
import {decode as atob, encode as btoa} from 'base-64'
import { API_KEY } from 'dotenv'
import axios from 'axios';
axios.get('...php', { crossdomain: true } , {
headers: {
"Access-Control-Allow-Origin": "*",
'Authorization': 'Basic ' + `${btoa(`${API_KEY}`)}`
}
})
.then(res => { ... })
PHP
$AUTH_USER = '...';
$AUTH_PASS = '...';
if (! empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
{
preg_match('/^Basic\s+(.*)$/i', $_SERVER['REDIRECT_HTTP_AUTHORIZATION'], $AUTH_PASS);
$str = base64_decode($AUTH_PASS[1]);
list( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) = explode(':', $str);
}
$has_supplied_credentials = !(empty($_SERVER['PHP_AUTH_USER']) && empty($_SERVER['PHP_AUTH_PW']));
$is_not_authenticated = (
!$has_supplied_credentials ||
$_SERVER['PHP_AUTH_USER'] != $AUTH_USER || $_SERVER['PHP_AUTH_PW'] != $AUTH_PASS
);
if ($is_not_authenticated) {
header('HTTP/1.1 401 Authorization Required');
header('WWW-Authenticate: Basic realm="Access denied"');
exit;
}
You can either write:
const usernameAndPassword = 'a:b'
axios.get('https://some_url', {
headers: {
Authorization: 'Basic ' + btoa(usernameAndPassword),
},
})
Or,
axios.get('https://some_url', {
auth: {
username: 'a',
password: 'b',
},
})
Both are same; will send exact same request headers:
To read the API_KEY i.e. username password from env file, you should name it as REACT_APP_API_KEY and then you can use it in your code as process.env.REACT_APP_API_KEY.
Client given below Ajax Post call, when i will open below PHP api file in browser then the static data is inserting correctly, now i am trying using Angular, but I am not able to understand how to convert this below call into component.ts and service
<?php
//creating payload parameters:
$classTitle = 'Demo Class on 3rd April, 2020';
$classInfo = 'This is a demo class scheduled to understand API';
$classDateTime = '2020-11-12 11:30 AM';
$timezone = 'Asia/Kolkata';
$classDuration = 15;
$classRecording = 'yes';
$classAutoStart = false;
$recordingAutoStart = false;
$classVideoRes = 720;
/*xyz.com*/
$apiKey = '12345';
$secretKey = '12345';
// Create token header as a JSON string
$header = json_encode(['alg' => 'HS256','typ' => 'JWT']); // ensure to place first alg part and next typ part
// Create token payload as a JSON string
$payload = json_encode(['classTitle' => $classTitle ,'classInfo' => $classInfo ,'classDateTime' => $classDateTime ,'timezone' => $timezone ,'classDuration' => $classDuration ,'classRecording' => $classRecording ,'classAutoStart' => $classAutoStart ,'recordingAutoStart' => $recordingAutoStart ,'classVideoRes' => $classVideoRes ,'apiKey' => $apiKey]);
// Encode Header to Base64Url String
$base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
// Encode Payload to Base64Url String
$base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
// Create Signature Hash
$signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, $secretKey , true);
// Encode Signature to Base64Url String
$base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
// creating JWT token variable
$jwt_token = $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;
// creating authorization varibale
$authorization = 'Bearer '.$jwt_token;
?>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript">
$.ajax
({
type: "POST",
url: 'https://xyz/client/schedule',
contentType: 'application/json',
data: JSON.stringify({
"apiKey": "12345"
}),
dataType : 'json',
headers: {
'authorization': '<?php echo $authorization; ?>'
},
success: function(retval)
{
// alert(retval);
console.log(retval);
// var success = retval.success;
}
});
</script>
I have updated Question and added after two replied answer
Below is my model class
export class Schedule1 {
classTitle: string;
classInfo: string;
classDateTime: string;
timezone: string;
classDuration: number;
classRecording:string;
classAutoStart: boolean;
recordingAutoStart: boolean;
classVideoRes: number;
constructor() {
}
}
Below is component.ts on button click passing static values
import { Schedule1 } from '../Models/Schedule1.model'
Schedule1: Schedule1 = new Schedule1();
addSchedule(scheduleForm: NgForm): void {
//static data parameter passing
this.Schedule1.classTitle='hi Class on 3rd April, 2020';
this.Schedule1.classInfo= 'This is a demo class scheduled to understand API';
this.Schedule1.classDateTime= '2020-11-12 11:30 AM';
this.Schedule1.timezone= 'Asia/Kolkata';
this.Schedule1.classDuration= 15;
this.Schedule1.classRecording= 'yes';
this.Schedule1.classAutoStart= false;
this.Schedule1.recordingAutoStart= false;
this.Schedule1.classVideoRes= 720;
//const data = JSON.stringify(this.Schedule1);
const data = {
apiKey: "dcbf187d-bdfe-431b-8f60-fa19bf51cd85",
data: JSON.stringify(this.Schedule1)
}
this.subscription = this.userSvc
.fetchData("https: //xyz.com/client/schedule", data)
.subscribe(
data => {
// Data on Success
console.log("data", data);
},
error => {
console.log("error", error);
}
);
}
Below is service.ts
fetchData(url: string, data: any): Observable<any> {
const headers = {
Authorization: "Bearer "+"1234",
"My-Custom-Header": "foobar",
contentType: "application/json"
};
return this.http.post(url, data, {
headers
});
}
in console getting this error.
Parsing HTTP request is pretty simple in Angular. Below are the steps you need to follow:
Step 1:
import the HttpClientModule in your app module like this:
import { HttpClientModule } from '#angular/common/http';
imports: [ HttpClientModule ]
Step 2:
Create a service for your application where you will store all the HTTP request calls.
NOTE: This part is not necessary as you can do HTTP calls directly in your component but for best practice and good structure this should be followed
So for this step, import HttpClient either in your service (if you have created) or in your component and then do like this below:
import { HttpClient } from '#angular/common/http';
constructor(private http: HttpClient) { }
createExamCategory(data) {
return this.http.post<{ message: string }>(this.url + '/category/create_exam', data);
}
Let me explain the createExamCategory() method.
The parameter data is the value that is coming from your HTML or any source. And this data will be passed in POST request.
The next line is as I am explaining with service I have just returned the call and will subscribe to it in the component.
The <{ message: string }> is the response that I am getting from the API request. If you are not sure what response you are getting you can just keep it as <any> and Angular will decide the type of response.
Then in the post method (this method is coming from HttpClient declared above) we have 2 pass to parameters by default & the third parameter which is HttpHeader is optional. The 2 parameters are:
URL OF the API.
The request body data for the POST request.
So that's all from the calling side now coming to the subscription part:
If you are directly writing the above part in component then continue with .subscribe(). Now for the service part:
Step 1:
Import the service:
import { SampleService } from 'sample.service';
constructor(private service: SampleService) { }
// Do the call where it is required. I am doing in a normal method
httpMethod() {
this.service.createExamCategory(data).subscribe(response => {
console.log(response); // This is the API response
});
}
Interceptor
import { HttpInterceptor, HttpErrorResponse, HttpEvent, HttpRequest, HttpHandler } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { catchError } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { Router } from '#angular/router';
import { Service } from 'service.service';
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private router: Router, private service: Service) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (sessionStorage.getItem('token')) {
const cloned = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + sessionStorage.getItem('token'))
});
return next.handle(cloned).pipe(
catchError((err, caught: Observable<HttpEvent<any>>) => {
if (err instanceof HttpErrorResponse && (err.status == 401))
{
this.adminAuthService.clearAuthData();
this.router.navigate(['required route path']);
alert('Session Timeout !! Login Again');
return of(err as any);
}
throw err;
})
);
}
return next.handle(req);
}
}
Here what I have done is while login/authentication I have stored the generated JWT token by the backend service in session and validated if the API url is valid or not.
After doing this in app.module.ts specify the interceptor in the providers like this:
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]
Hoping this will help you 🙂
create a service like below.
import { Injectable } from "#angular/core";
import { HttpClient } from "#angular/common/http";
import { Observable } from "rxjs";
#Injectable({
providedIn: "root"
})
export class ScheduleDataService {
constructor(private _http: HttpClient) {}
fetchData(url: string, data: any): Observable<any> {
const headers = {
Authorization: "Bearer my-token",
"My-Custom-Header": "foobar",
contentType: "application/json"
};
return this._http.post(url, data, {
headers
});
}
}
then you can call this service in your component like below.
import { Component, OnDestroy, OnInit, VERSION } from "#angular/core";
import { ScheduleDataService } from "./schedule-data.service.ts";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit, OnDestroy {
name = "Angular " + VERSION.major;
private subscription;
constructor(private _scheduleDataService: ScheduleDataService) {}
ngOnInit() {
this.subscription = this._scheduleDataService
.fetchData("https://xyz/client/schedule", {
apiKey: "myapikey"
})
.subscribe(
data => {
// Data on Success
console.log("data", data);
},
error => {
console.log("error", error);
}
);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
Let me know if you have any doubt.
You can Create service Like and call in component.
services.ts
import { HttpClient, HttpHeaders } from '#angular/common/http';
#Injectable({
providedIn: "root"
})
export class UserService{
constructor(public http: HttpClient){}
let headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': ''
});
public getData(url: string, data: any): Observable<any> {
return this.http.post(url, data, { headers: headers});
}
}
components.ts
import { Component, OnInit } from '#angular/core';
import { UserService } from './services.ts';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class Components implements OnInit {
constructor(public userService: UserService){}
public ngOnInit(): void {
const data = { apiKey: "myapikey" }
this.userService.getData(url, data).subscribe((res)=>{
code...
})
}
}
Just a map to store post request body
var rqstParameters = {
'email': '',
'loginMethod': '',
'name': '',
'token': ''
};
Google Login triggered on this button pressed
return RaisedButton(
onPressed: () {
authService.googleSignIn().then((user) {
user.getIdToken(refresh: true).then((usrTokenId) {
rqstParameters['email'] = user.email;
rqstParameters['loginMethod'] = '4';
rqstParameters['name'] = user.displayName;
// printWrapped(usrTokenId.token);
rqstParameters['token'] = usrTokenId.token;
}).whenComplete(() {
fetchPost().then((response) {
var body = response.body;
print(body);
});
});
});
},
color: Colors.transparent,
child: Text(
'Signin with GOOGLE',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
);
Request Looks like this--->
Future<http.Response> fetchPost() async {
// print(rqstParameters);
final response = await http.post(
'https://this/is/the_server.in/dashboard/login.php',
headers: {'Accept': 'application/json'},
body: rqstParameters,
);
print(response.statusCode);
return response;
}
This is Authentication Logic used for Google Signin
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:rxdart/rxdart.dart';
class AuthService {
FirebaseUser mCurrentUser;
final GoogleSignIn _googleSignIn = GoogleSignIn();
final FirebaseAuth _auth = FirebaseAuth.instance;
// Shared State for Widgets
Observable<FirebaseUser> user; // firebase
PublishSubject loading = PublishSubject();
// constructor
AuthService() {
user = Observable(_auth.onAuthStateChanged);
}
Future<FirebaseUser> googleSignIn() async {
loading.add(true);
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
final AuthResult result = await _auth.signInWithCredential(credential);
final FirebaseUser user = result.user;
// Done
loading.add(false);
print("signed in as " + user.displayName );
return user;
}
void signOut() {
_auth.signOut();
}
final AuthService authService = AuthService();
This is the response body i am getting back from server-->
{"email":"example#question.com","name":"Users Display Name","token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjI1MDgxMWNkYzYwOWQ5MGY5ODE1MTE5MWIyYmM5YmQwY2ViOWMwMDQiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiVmlkeWkjfhjkEgUHJha2FzaCBBd2FzdGhpIiwjxdfbicGljdHVyZSI6Imh0dHBzOi8vbGg2Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tYjJoZ20yeFNfRlkvQUFBQUFBQUFBQUkvQUFBQUFBQUFBQUEvQUNIaTNyZTZwMXlBQVlUXzNQUkwyVWFGczlDQXNwcElCdy9zOTYtYy9waG90by5qcGciLCJpc3MiOiJodHRwczovL3NlY3VyZXRvaskdlfjkl2VuLmdvb2dsZS5jb20vdGF4aGVhbGlubWFjaGluZSIsImF1ZklsdfjklCI6InRheGhlYWxpbm1hY2hpbmUiLCJhdXRoX3RpbWUiOjE1NzM2ODM0MzIsInVzZXJfaWQiOiJRTmVUT3cyRnpraEJhczRQQVM3S2lwTWhNVFcyIiwic3ViIjoiUU5lVE93MkZ6a2hCYXM0UEFTN0tpcE1oTVRXMiIsImlhdCI6MTU3MzY4MzQzMywiZdkjfhkjXhwIjoxNTczNjg3MDMzLCJlbWFpbCI6InByYWthc2h2aWR5YTY4QGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJmaXJlYmFzZSI6eyJpZGVudGl0aWVzIjp7Imdvb2dsZS5jb20iOlsiMTE0MzE5MjI5ODQ1NTEyOTYsdgf5MzAwIl0sImVtYWlsIjpbInByYWthc2h2aWR5YTY4QGdtYWlsLmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6Imdvb2dsZS5jb20ifX0.NBuuCCtFMjBQghBjEDajSyEqbBYF567yN3u7fk1gCx8nzrVAYyVLc1f7zQoId0dsjfjahPnnMoTpU3mAdrL-PyWgJIwxI4WjKNyhhAy9XXgWZa8gUb5APAPYbcomPxiuThrE8-Bfkr-vdSTkviwRLzk2XKCNi-wtXGYrikQ34Rj5FzmRsPzGa6dLICyB-qyhbAOwQ-jhjsdhfuCMgUISseyl-ol5Ua_RnE7KHwdjNxTvVdnax_cT42uY88cpGGQc3JksdjhfrKAvTe19dzu092kMVnG91euFMBUQw2Nu6a6cdq7k4vz-egZd1IMIwkrmSQiRQihG3ODEOhPPuuo2lEsO7iHMldF3c4D_oA","payload":false,"error":"payload not verified"}
server uses this PHP code to verify client
$client = new Google_Client(['client_id' => $CLIENT_ID]);
$payload = $client->verifyIdToken($id_token);
if ($payload) {
//login Successful
} else {
// payload not verified
// login Failed
}
Why payload is not getting verified when the tokens are all sent correctly and proper flow is maintained...please help.. :(
I am trying to send some JSON data(Fetched From DaynamoDB) to another server from AWS lambda function but while giving the URL in the script :
'use strict';
const https = require('https');
exports.handler = (event, context, callback) => {
var options = {
hostname: 'https://www.corecomputersystem.com',
path: '/getSyncData.php',
port : 432,
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
};
event.Records.forEach((record) => {
console.log(record.eventID);
console.log(record.eventName);
console.log('DynamoDB Record: %j', record.dynamodb);
var res = record.dynamodb;
const req = https.request(options, (res) => {
let body = "";
console.log('Status:', res.statusCode);
console.log('Headers:', JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', (chunk) => body += chunk);
res.on('end', () => {
console.log('Successfully processed HTTPS response');
// If we know it's JSON, parse it
if (res.headers['content-type'] === 'application/json') {
body = JSON.parse(body);
}
callback(null, body);
});
});
req.on('error', callback);
req.write(JSON.stringify(event.data) + "");
req.end();
//context.succeed();
});
};
it's throwing following error,
{
"errorMessage": "getaddrinfo ENOTFOUND https://www.corecomputersystem.com https://www.corecomputersystem.com:432",
"errorType": "Error",
"stackTrace": [
"errnoException (dns.js:26:10)",
"GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:77:26)"
]
}
and if I uncomment the context.succeed(), there is no error, I need help for identifying the error.
Just for deeply with #at0mzk says, a hostname never take any port number, so any prefix like [http, https, smb, nfs]:// will throw an error any where a hostname is requested.
(http://localhost === localhost:80)
remove https:// from hostname variable.
var options = {
hostname: 'www.corecomputersystem.com',
path: '/getSyncData.php',
port : 432,
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
see docs.
Before making HTTPS request we can use :
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
so it will not ask for authorization.
Another way we can add a key in option before requesting HTTP:
rejectUnauthorized: false
It will not ask for self asigned certificate.
This is what I was searching for.
This worked for me.
In lambda use the following node js.
const https = require('https');
var querystring = require("querystring");
const doPostRequest = (event) => {
//parameters to post
const params = {
name: "John",
title: "Developer",
userid: 123
};
var qs = querystring.stringify(params);
var qslength = qs.length;
return new Promise((resolve, reject) => {
const options = {
host: 'example.com',//without https or http
path: '/yourpath/yourfile.php',
method: 'POST',
port: 443, // replace with 80 for HTTP requests
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': qslength
}
};
var buffer = "";
//create the request object with the callback with the result
const req = https.request(options, (res) => {
resolve(JSON.stringify(res.statusCode));
res.on('data', function (chunk) {
buffer+=chunk;
});
res.on('end', function() {
console.log(buffer);
});
});
// handle the possible errors
req.on('error', (e) => {
reject(e.message);
});
//do the request
req.write(qs);
//finish the request
req.end();
});
};
exports.handler = async (event) => {
try {
const result = await doPostRequest(event);
console.log('result is:️ ', result);
//️️ response structure assume you use proxy integration with API gateway
return {
statusCode: 200,
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(result),
};
} catch (error) {
console.log('Error is:️ ', error);
return {
statusCode: 400,
body: error.message,
};
}
};
For some reason lambda didnt show the response for me other than 200. So I had to create a logfile on my server to verify that it was sending the POST values. From there you can use json_encode to show the posted string or just echo the POST values
$inputJSON = json_encode($_POST);
$input = json_decode($inputJSON, TRUE);
$log = "Data: ".$_SERVER['REMOTE_ADDR'].' - '.date("F j, Y, g:i a").PHP_EOL.
"Data: ".$inputJSON.PHP_EOL.
"Data: ".$input.PHP_EOL.
"Data: ".$_POST['name'].PHP_EOL.
"Data: ".$_POST['title'].PHP_EOL.
"Data: ".$_POST['userid'].PHP_EOL.
"-------------------------".PHP_EOL;
//Save string to log, use FILE_APPEND to append.
file_put_contents('./log_'.date("j.n.Y").'.log', $log, FILE_APPEND);
i have set up the normal CSRF stuff etc and would work well, but then when i go and use ajax using the whatwg-fetch api (https://github.com/github/fetch)
Now all seem ok and all works well to what i have. BUT! Then I add the CSRF settings as below and it fails, all the time:
So, I have used the normal, but it fails and in the header I get the message: Failed CSRF check!
$app->add(new \Slim\Csrf\Guard);
But I wanted to add own message etc so have added the following, but still it does not pass.
$container['csrf'] = function ($c) {
$guard = new \Slim\Csrf\Guard;
$guard->setFailureCallable(function ($request, $response, $next) {
$request = $request->withAttribute("csrf_status", false);
return $next($request, $response);
});
return $guard;
};
$app->add($container->get('csrf'));
Then in my class i check it with:
if (false === $req->getAttribute('csrf_status')) {...}else{//all ok}
But what ever happens it always fails.
in my js i am adding the token details to the request like:
fetch('/post/url',{
method: 'POST',
headers: {
'X-CSRF-Token': {
'csrf_name':csrf_name,
'csrf_value':csrf_value
}
},
body: new FormData(theForm)
i have looked in the posted data etc and the form data is submitted including the csrf values etc. SO the require csrf data is being sent via the form as well as the header?
So how can I get the ajax functionality to work with the Slim CSRF, what am I missing?
Thanks in advance
I was also unable to get fetch to put the tokens into the body. I decided to extend the class so I could modify the __invoke method. I have added some code to pull the csrf from the headers.
in your dependencies now use this class.
$c['csrf'] = function ($c) {
return new \Foo\CSRF\Guard;
};
The extended class.
<?php
namespace MYOWN\CSRF;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* CSRF protection middleware.
*/
class Guard extends \Slim\Csrf\Guard
{
public function __construct(
$prefix = 'csrf',
&$storage = null,
callable $failureCallable = null,
$storageLimit = 200,
$strength = 16,
$persistentTokenMode = false
) {
parent::__construct(
$prefix,
$storage,
$failureCallable,
$storageLimit,
$strength,
$persistentTokenMode);
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
$this->validateStorage();
// Validate POST, PUT, DELETE, PATCH requests
if (in_array($request->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
$body = $request->getParsedBody();
$body = $body ? (array)$body : [];
$name = isset($body[$this->prefix . '_name']) ? $body[$this->prefix . '_name'] : false;
$value = isset($body[$this->prefix . '_value']) ? $body[$this->prefix . '_value'] : false;
if (!empty($csrfTokens = $request->getHeader('x-csrf-token'))) {
$csrfTokens = json_decode($csrfTokens[0], true);
$name = isset($csrfTokens[$this->prefix . '_name']) ? $csrfTokens[$this->prefix . '_name'] : false;
$value = isset($csrfTokens[$this->prefix . '_value']) ? $csrfTokens[$this->prefix . '_value'] : false;
}
if (!$name || !$value || !$this->validateToken($name, $value)) {
// Need to regenerate a new token, as the validateToken removed the current one.
$request = $this->generateNewToken($request);
$failureCallable = $this->getFailureCallable();
return $failureCallable($request, $response, $next);
}
}
// Generate new CSRF token if persistentTokenMode is false, or if a valid keyPair has not yet been stored
if (!$this->persistentTokenMode || !$this->loadLastKeyPair()) {
$request = $this->generateNewToken($request);
}
// Enforce the storage limit
$this->enforceStorageLimit();
return $next($request, $response);
}
}
well after several attempts over the last day and narrowing it down to the fetch api was using I decided to go back to the trusted jQuery aJax methods, and this seems to have worked.
Seems the following body and the new FormData() was not being picked up:
fetch('/post/url',{
method: 'POST',
body: new FormData(theForm)
So switched it out for
$.ajax({
url : '/url/to/post',
type: "POST",
data: {key:value, kay:value}
And all worked well.
The next issue to look into then is the keys being refreshed on first ajax call, preventing anymore calls unless page is refreshed, but thats for another day
I had another go at this after reading one of the blogs from one of the creators. So you can ignore my previous answer.
Sending the csrf in the body with these headers passes the csrf check.
const data = {
'csrf_name': csrf_name,
'csrf_value': csrf_value,
};
fetch(apiUrl, {
method: 'POST',
credentials: 'include',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded; charset=utf-8',
},
}).then((response) => {
if (response.ok) {
return response.json();
}
return null;
}).then((json) => {
console.log(json);
}).catch(() => {
});
What finally helped me succeed with Slim PHP and the CSRF values while using fetch was adding credentials: 'include' to the fetch request, like:
const body = JSON.stringify({
csrf_name: csrfName.value,
csrf_value: csrfValue.value
// You can add more data here
});
fetch('/some/request', {
method: 'POST',
body: body,
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
}).then(...)