Ionic 2 - Include Authorization header in all api calls - http

My Ionic 2 app have few providers and they communicate with a secured API over http, so I have to include an authorization header contains bearer token (which I stored in localstorage) with every request I made.
My current (ugly) implementation is for each function, am appending header like below sample code,
getAccountDetails(accountId: string): Promise<any> {
let url = API_ENDPOINT + 'some-string';
return new Promise(resolve => {
this.userData.hasLoggedIn().then((hasLoggedIn) => {
if (hasLoggedIn) {
this.userData.getUserToken().then((token) => {
let headers = new Headers();
headers.append('Authorization', 'Bearer ' + token);
this.http.post(url, { id: accountId }, { headers: headers }).map(res => res.json()).subscribe(data => {
resolve(data);
});
})
}
})
});
}
As I mentioned above, for each functions now I repeat the same header append code, how can I make it DRY (avoid repeating the same code)?

Related

Fetching resources from google analytics services using HTTPS by Wix fetch function

How should I fetch data using Wix-fetch function?
I followed this google analytics API tutorial, this tutorial using post function for getting JSON data, I used WIX fetch function to get JSON file, but the return object is undefined.
What did I miss?
fetch( "https://accounts.google.com/o/oauth2/token", {
"method": "post",
"headers": {
"Content-Type": 'application/x-www-form-urlencoded'
},
'body' : JSON.stringify({
'grant_type': 'authorization_code',
'code': URLCode,
'client_id': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
'client_secret': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'redirect_uri': 'https://www.mydomain.or/ga/oauth2callback'
})
} )
.then( (httpResponse) => {
if (httpResponse.ok) {
return httpResponse.json();
} else {
return Promise.reject("Fetch did not succeed");
}
} )
.then( (json) => console.log(json.someKey) )
.catch(err => console.log(err));
UPDATE
STEP 1
I used this URL to generate the CODE
wixLocation.to("https://accounts.google.or/o/oauth2/auth?scope=https://www.googleapis.com/auth/analytics%20https://www.googleapis.com/auth/userinfo.email&redirect_uri=https://www.mydomain.or/ga/oauth2callback/&access_type=offline&response_type=code&client_id=XXXXXXXXXXXXXXXXXX")
I get the CODE from the callback URL
Step 2
I used this code for the HTTP postman request
The redirect URI in step 1 and 2 is the following (the second one):
Step 1:
There needs to be an exact match between the redirect URI configured in the client id in the google developers console and the URL to get the code authorization.
The URL should be built as shown in the tutorial you linked (if you need a refresh token, you can add the access_type=offline)
https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/analytics&redirect_uri=<redirect_uri>&response_type=code&client_id=<client_id>
After you enter the URL, you will be provided with an authorization window. Once you authorize, you will be redirected to the <redirect_uri> you provided earlier. You will find the code as the first parameter in the URL query. e.g. <redirect_uri>/?code=<auth_code> ...
Since the access token is for one-time use only, if you will need it again, you will have to get a new <auth_code>.
Step 2 (Postman query example):
If you got the access_token correctly and you want to check now with WIX. Get a new <auth_code> (as said, the access token is given once) and set the code as follows:
import { fetch} from 'wix-fetch';
$w.onReady(function () {
const data = `grant_type=authorization_code&code=<your_authorization_code>&client_id=<your_client_id>&client_secret=<your_client_secret>&redirect_uri=<your_redirect_uri>`;
fetch("https://accounts.google.com/o/oauth2/token", {
"method": "post",
"headers": {
"Content-Type": 'application/x-www-form-urlencoded'
},
'body': data
})
.then((httpResponse) => {
if (httpResponse.ok) {
return httpResponse.json();
} else {
return Promise.reject("Fetch did not succeed");
}
})
.then((json) => console.log(json.access_token))
.catch(err => console.log(err));
});

How to pass Custom Header from React JS client to SignalR hub?

I am setting up a new SignalR react app ("#aspnet/signalr") with Dot Net Core 2.0. I want to send custom headers to SignalR hub "negotiate" request (like request.headers["MyHeader"] = "Header").
I am able to connect to hub and get data back to react app. I have tried setting custom header by trying to overwrite httpClient in options passed to "withUrl".
With the code provided here I am getting error: "Error: Failed to complete negotiation with the server: Error: Unexpected status code returned from negotiate undefined"
It connects when httpClient is removed from options.
import { HubConnectionBuilder } from '#aspnet/signalr';
const options = {
accessTokenFactory: () => {
return "jwt token";
},
httpClient: {
post: (url, httpOptions) => {
httpOptions.headers = {
...httpOptions.headers,
MyHeader: "NewHeader"
};
httpOptions.method = "POST";
httpOptions.url = url;
return httpOptions;
}
}
};
const connection = new HubConnectionBuilder()
.withUrl("https://localhost:5001/chatHub", options)
.build();
connection.start().catch(function(err) {
console.log("Error on Start : ", err);
});
The way I see header as "Authorize": "jwt token", I expect to see another header in "https://localhost:5001/chatHub/negotiate" request as "MyHeader": "NewHeader"
Found answer to this.
httpClient.post overwrites the response of default SignalR httpClient.post.
Below update to httpClient worked.
httpClient: {
post: (url, httpOptions) => {
const headers = {
...httpOptions.headers,
MyHeader: "MyHeader"
};
return axios.post(url, {}, { headers }).then(response => {
return (newResponse = {
statusCode: response.status,
statusText: response.statusText,
content: JSON.stringify(response.data)
});
});
}
}
SignalR "negotiate" expects response in this form.
{
statusCode: 200,
statusText: "ok",
content: "<string response>"
}

Angular5 Response Header (Content-Disposition) Reading

How Can I read Response Header (Content-Disposition)? Please share resolution.
When I check at either Postman or Google Chrome Network tab, I can see 'Content-Disposition' at the response headers section for the HTTP call, but NOT able to read the header parameter at Angular Code.
// Node - Server JS
app.get('/download', function (req, res) {
var file = __dirname + '/db.json';
res.set({
'Content-Type': 'text/plain',
'Content-Disposition': 'attachment; filename=' + req.body.filename
})
res.download(file); // Set disposition and send it.
});
// Angular5 Code
saveFile() {
const headers = new Headers();
headers.append('Accept', 'text/plain');
this.http.get('http://localhost:8090/download', { headers: headers })
.subscribe(
(response => this.saveToFileSystem(response))
);
}
private saveToFileSystem(response) {
const contentDispositionHeader: string = response.headers.get('Content-Disposition'); // <== Getting error here, Not able to read Response Headers
const parts: string[] = contentDispositionHeader.split(';');
const filename = parts[1].split('=')[1];
const blob = new Blob([response._body], { type: 'text/plain' });
saveAs(blob, filename);
}
I have found the solution to this issue. As per Access-Control-Expose-Headers, only default headers would be exposed.
In order to expose 'Content-Disposition', we need to set 'Access-Control-Expose-Headers' header property to either '*' (allow all) or 'Content-Disposition'.
// Node - Server JS
app.get('/download', function (req, res) {
var file = __dirname + '/db.json';
res.set({
'Content-Type': 'text/plain',
'Content-Disposition': 'attachment; filename=' + req.body.filename,
'Access-Control-Expose-Headers': 'Content-Disposition' // <== ** Solution **
})
res.download(file); // Set disposition and send it.
});
It is not the problem with Angular, is the problem with CORS.
If the server does not explicitly allow your code to read the headers, the browser don't allow to read them.
In the server you must add Access-Control-Expose-Headers in the response.
In the response it will be like Access-Control-Expose-Headers:<header_name>,
In asp.net core it can be added while setting up CORS in ConfigureServices method in startup.cs
this solution help me to get the Content-Disposition from response header.
(data)=>{ //the 'data' is response of file data with responseType: ResponseContentType.Blob.
let contentDisposition = data.headers.get('content-disposition');
}
Firstly you need to allow your server to expose these headers. Note that it will show in you browser network tab, regardless if you have these settings. This makes it 'available'.
With C# it would look something like this:
services.AddCors(options => {
options.AddPolicy(AllowSpecificOrigins,
builder => {
builder
.WithOrigins("http://localhost:4200")
.AllowAnyHeader()
.AllowAnyMethod()
.WithExposedHeaders("Content-Disposition", "downloadFileName");
});
});
When you send your API request to the server ensure that you include the "observe" in you return. See below:
getFile(path: string): Observable<any> {
// Create headers
let headers = new HttpHeaders();
// Create and return request
return this.http.get<Blob>(
`${environment.api_url}${path}`,
{ headers, observe: 'response', responseType: 'blob' as 'json' }
).pipe();
}
Then in your response of your angular on your subscribe you can access your filename like this (the subscribe method is not complete it attaches to a pipe function)
.....
.subscribe((response: HttpResponse<Blob>) => {
const fileName = response.headers.get('content-disposition')
.split(';')[1]
.split('filename')[1]
.split('=')[1]
.trim();
});

angular2 wait for error http response

I have a problem with angular2 http response.
I want to catch the error in my component.
How does my app work.
In my Component, I Call a function in a personal service :
var response = this.apiUser.login(username, password);
alert(response);
In my Service, I try to auth :
this.http.post(this.httpApiAdress + '/' + this.httpUserAutenticate, body, { headers: contentHeaders })
.subscribe(
response => {
localStorage.setItem('id_token', response.json().token);
this.router.navigate(['home']);
},
error => {
return error.json();
},
() => { }
);
When the auth is ok, all work fine. But when the Auth fail, i can't catch the response in my Component.
(Its undefinied because the alert is executed before the http call...)
Can u help me please !!! (It was working when all the code was only in my Component, but I wanted to slip my code...)
Ty.
Return the observable by using map() instead of subscribe()
return this.http.post(this.httpApiAdress + '/' + this.httpUserAutenticate, body, { headers: contentHeaders })
.map(
response => {
localStorage.setItem('id_token', response.json().token);
this.router.navigate(['home']);
},
);
and then use subscribe where you want to execute code when the response or error arrives
var response = this.apiUser.login(username, password)
.subscribe(
response => alert(response),
error => alert(error),
);

How to recognise an existing Google OAuth authentication made via Firebase and perform a Google Directory API request in Angular 2?

I want to use my existing authentication and be able to use that same authentication to perform a get request to the Google Directory API. Here's my current code:
login() {
this.firebaseRef = new Firebase('https://xxx.firebaseio.com');
this.firebaseRef.authWithOAuthPopup("google", (error, authData) => {
if (error) {
console.log("Login Failed!", error);
} else {
console.log("Authenticated successfully with payload:", authData);
}
}, {
scope: "https://www.googleapis.com/auth/admin.directory.user.readonly"
});
}
getData() {
// TO-DO
// Recognise existing OAuth and perform a GET request to
// https://www.googleapis.com/admin/directory/v1/users?domain=nunoarruda.com
}
You could leverage the getAuth method on the firebaseRef instance. Something like that:
getData() {
var authData = this.firebaseRef.getData();
var provider = authData.provider;
// In your case provider contains "google"
}
See this documentation: https://www.firebase.com/docs/web/api/firebase/getauth.html.
I've found the solution. I need to use the current access token in the http request headers for the GET request.
import {Http, Headers} from 'angular2/http';
getData() {
// get access token
let authData = this.firebaseRef.getAuth();
let oauthToken = authData.google.accessToken;
console.log(oauthToken);
// set authorization on request headers
let headers = new Headers();
headers.append('Authorization', 'Bearer ' + oauthToken);
// api request
this.http.get('https://www.googleapis.com/admin/directory/v1/users?domain=nunoarruda.com',{headers: headers}).subscribe((res) => {
console.log(res.json());
});
}

Resources