Ionic 2 - How to use refresh token to obtain new JWT - javascript

I have an ionic 2 mobile application that uses Json Web Tokens(JWT) to authenticate to various routes on a node.js API. These JWTs have a short expire time, and need to be refreshed using a refresh token. The refresh token is just a random string that is stored both in the database and on the mobile device. Please note: I am NOT using OAuth.
How can I refactor my API calls so that they all go through one method which will send a refresh token if the initial API call gets a 401 Unauthorized response due to an expired JWT? Otherwise, I will need to write the logic for handling that response in every single API call which I would like to avoid.
Here is an example of one method I have implemented in typescript that calls the API. It is not currently handling a 401 Unauthorized response nor is it sending the refresh token yet:
public setBeerPref(beerPrefs) {
return new Promise((resolve, reject) => {
this.storage.get('email').then((email) => {
this.storage.get('token').then((token) => {
beerPrefs["email"] = email;
let headers = new Headers();
headers.append('Authorization', token);
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({ headers: headers });
this.http.post('apiURL', beerPrefs, options)
.subscribe(res => {
let data = res.json();
resolve(data);
resolve(res.json());
}, (err) => {
reject(err);
});
});
});
});
}

Related

Discord.js: can't fetch user's connections (OAuth2)

I have a Discord app/bot with a custom linked role, and before updating metadata and adding the role, I want to fetch user's connections and look at some data from it.
More specifically, I want to assign a custom role only to users who own a specific game on Steam and have certain achievements from it. Currently stuck at fetching connections part - OAuth in general works fine.
Took this example discord oauth app:
https://github.com/discord/linked-roles-sample
And it works, except for this part: I want to fetch user's connections
Added this new function
export async function getUserConnections(tokens) {
const url = 'https://discord.com/api/v10/oauth2/#me/connections';
const response = await fetch(url, {
method: 'GET',
headers: {
Authorization: `Bearer ${tokens.access_token}`,
},
});
if (response.ok) {
const data = await response.json();
return data;
} else {
throw new Error(`Error fetching user connections: [${response.status}] ${response.statusText}`);
}
}
But this fetch always returns 404, even though scope for connections is defined

Pass firebase access token to backend in axios interceptor

I need some help understanding how to pass in a firebase bearer/jwt token with my api requests to the backend.
I am using axios and using an interceptor to set up the bearer token similar to this
axios.interceptors.request.use(
config => {
const userData = store.getters['firebaseAuth/user']
if (userData && userData.accessToken) {
config.headers['Authorization'] = 'Bearer ' + userData.accessToken
}
In all the examples for firebase auth, I have seen that the way to get the jwt token is like so:
firebase
.auth()
.currentUser.getIdToken(/* forceRefresh */ true)
.then(idToken => {
Would it be good practice to run this in my interceptor to obtain the access token?..
Feels like an unnecessary extra api call to firebase servers for every request made to my backend server.
Also I have trouble understanding why I should even use this firebase method (getIdToken) when the token is available as a property from the user object. It has a strange name "za" which i think is deliberate from firebase, and nowhere mentions to use this to get the id/bearer/access token.
firebase.auth().onAuthStateChanged(user => {
if (user) {
//user.za id the id/bearer/access token
My initial thought was to just store user.za in localstorage then fetch it from local storage in the interceptor.
I'm not sure if it is the best way, but I ended up using the Firebase SDK methods in my interceptor directly. My understanding of the getIdToken API is that the promise returns a cached JWT, unless it is expired, in which case it will return a fresh one. I made the interceptor function async, and use await to synchronously request the token.
axios.interceptors.request.use(
async function (request) {
const user = currentUser();
if (user) {
try {
const token = await user.getIdToken(false); // Force refresh is false
request.headers["Authorization"] = "Bearer " + token;
} catch (error) {
console.log("Error obtaining auth token in interceptor, ", error);
}
}
return request;
},...

Refresh and access token flow in JWT

I have developed a standard JWT system that logs in and issues an access token and a refresh token. The access token expires after a short amount of time and there is a route to refresh the token.
I use axios to make requests but I am not sure how to deal with expired tokens. For example, if I make a request to /secret_route with my access token and it's expired, do I need to wait for a 403 and then make a request to /refresh_token and then make the original request again? Seems messy from a programming point of view and quite wasteful on the network. Is there an efficient/elegant way to do this?
I ended up with a solution that I feel is more robust than checking the timestamp. Thanks #Bergi but I am concerned about the system clock. I use axios interceptors to refresh the token on a 401
// Request interceptor for API calls
axios.interceptors.request.use(
async config => {
config.headers = {
'Authorization': `Bearer ${localStorage.getItem("accessToken")}`,
'Accept': 'application/json',
}
return config;
},
error => {
Promise.reject(error)
});
// Allow automatic updating of access token
axios.interceptors.response.use(response => response, async (error) => {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
const res = await axios.post('/users/token', { token: localStorage.getItem('refreshToken') });
setToken(res.data.accessToken);
return axios.request(originalRequest);
}
return Promise.reject(error);
});
Adapted from https://thedutchlab.com/blog/using-axios-interceptors-for-refreshing-your-api-token

Javascript AzureAd Consume Rest Service

RestAPI: I have a Rest API running Asp Core with AzureAd Authentication.
WebApp: I have a separate WebApplication running Asp Core as backend, with Javascript frontend.
The WebApp backend authenticates through AzureAd, and then against the RestAPI to check if a user is registred.
I want the javascript client to be able to consume the Rest API directly. How should i go about this without exposing the accesstoken?
I could go about sending the request from Javascript to WebApp Backend -> Rest API. But i really want to avoid this, because of unnecessary code.
In this scenario, you can try to implement ADAL for js in your JS client. Leveraging **adal** to gain the authentication token, and when you call your Web Api, it will add the authentication header in HTTP requests.
E.G.
Suppose we want to call the Microsoft Graph API from our JS client.we develop a node.js script that uses request to call the Microsoft Graph API for groups to create a new Security Group.
The following code shows how the API is consumed from that script. Note that the token and the name are passed by parameter. Additionally, this function returns a Promise that is successfully resolved when the group is correctly created and rejected when is not.
var request = require('request');
function createGroup(token, name) {
return new Promise((resolve, reject) => {
const options = {
method: 'POST',
url: 'https://graph.microsoft.com/v1.0/groups/',
headers: {
'Authorization': 'Bearer ' + token,
'content-type': 'application/json'
},
body: JSON.stringify({
"displayName": name,
"mailEnabled": false,
"securityEnabled": true
})
};
request(options, (error, response, body) => {
const result = JSON.parse(body);
if (!error && response.statusCode == 204) {
resolve(result.value);
} else {
reject(result);
}
});
});
}
In order to call Microsoft Graph API, we needed to be authenticated and that is why in the previous section we have a token as a parameter of the function which was used to perform the request.
we should add the following code to generate the token. Note that we are using the adal npm package to do this easier, calling the acquireTokenWithClientCredentials method of the AuthenticationContext object. Additionally, we have some constants that need to be updated with the client id and secret obtained before as well as the tenant name.
var adal = require('adal-node');
const TENANT = "{tenant-name-here}.onmicrosoft.com";
const CLIENT_ID = "{Application-id-here}";
const CLIENT_SECRET = "{Application-key-here}";
function getToken() {
return new Promise((resolve, reject) => {
const authContext = new adal.AuthenticationContext(`https://login.microsoftonline.com/${TENANT}`);
authContext.acquireTokenWithClientCredentials(GRAPH_URL, CLIENT_ID, CLIENT_SECRET, (err, tokenRes) => {
if (err) { reject(err); }
resolve(tokenRes.accessToken);
});
});
Hope it helps.

How to fix/find 'Bad Request' and 'Denied' authentication errors in react

I am working on a user registration page in my group project and came across a bad request error when submitting the data. I created a button to get users so I can check the authentication and it gave me a 401. "HTTP401: DENIED - The requested resource requires user authentication. (Fetch)GET - http://localhost:49967/Users" When I login, I use the admin login that's in the database and I see a token in my developers options. How do I find this error? I am new to react and programming so if you can lend some advice or docs it would be appreciated.
So to test my api endpoint, I loaded Postman and attempted to GET/POST and everything worked. I am using a react front-end, SQL sever for the database and ASP.Net Core in Visual Studios c#.
For starters here is the const I am using to access the back end
const apiHelper = {
get(url, params){
return fetch(`${baseUrl}${url}`, {
headers: this.headers
})
.then(response => response.json())
.catch(error => {
console.log(error);
return Promise.resolve();
});
}
This is the onclick action
handleGetUsers = async() => {
const response = await apiHelper.get('Users')
if(response){
console.log(response)
}
}
Lastly my URL
http://localhost:49967/

Categories