I am trying to create a JWT for Firebase authentication using the server side javascript language: jaggeryJS.
Below I will outline
My approach to the JWT creation
The front-end response.
1 My approach to the JWT creation
HmacSHA256 function comes from Google's CryptoJS library and the Base64.encode is as outlined [here][3] but adding a second parameter to allow for websafe escaping.
<%
//create a jwt
//==============================================
//INCLUDES
include('../lib/config.js');
include('../lib/crypto/hmac-sha256.js');
include('../lib/crypto/base64.js');
//==============================================
// HEADER
var header = {
"alg": "HS256",
"typ": "JWT"
}
//==============================================
// CLAIMS
var claims = {
"v": 0,
"iat": Math.floor(new Date().getTime() / 1000),
"d": {"user":"test"},
"exp": (60 * 60 * 24 * 60),
"admin": true,
"debug": true
}
//PREPARE SIGNING
var headerBase64 = Base64.encode(stringify(header), true),
claimBase64 = Base64.encode(stringify(claims), true),
signingInput = headerBase64 + "." + claimBase64;
//CREATE SIGNATURE
var hash = CryptoJS.HmacSHA256(signingInput, FIREBASECONFIG.secret).toString(),
signature = Base64.encode(hash, true);
//CONSTRUCT JWT ('jot') TOKEN
var jwtToken = signingInput + "." + signature;
print(jwtToken);
2 The front-end response.
var dataRef = new
Firebase("https://intense-heat-2343.firebaseio.com");
var AUTH_TOKEN = "...." //what is printed above "jwtToken"
dataRef.auth(AUTH_TOKEN, function(error) { if(error) {
console.log("Login Failed!", error); } else {
console.log("Login Succeeded!"); } });
CONSOLE OUTPUT:
Login Failed! Error {code: "INVALID_TOKEN", stack: (...), message:
"INVALID_TOKEN: Could not parse auth token."}
When I pass my secret in directly I am able to authenticate successfully. Any help is appreciated. Thank you!
Related
I am trying to send a https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-id api to obtain some user info, but the response is always
{
statusCode: 403,
data: '{\n' +
' "title": "Unsupported Authentication",\n' +
' "detail": "Authenticating with Unknown is forbidden for this endpoint. Supported authentication types are [OAuth 1.0a User Context, OAuth 2.0 Application-Only, OAuth 2.0 User Context].",\n' +
' "type": "https://api.twitter.com/2/problems/unsupported-authentication",\n' +
' "status": 403\n' +
'}'
}
Even though I have successfully have the oauth_access_token and oauth_access_secret as described in https://developer.twitter.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens
Below is my code snippet to send the request;
// server.js
app.get('/api/twitter/temp/profile', async (req, res) =>{
const { oauth_access_token, oauth_access_token_secret } = access_tokens[tmp_token];
try {
// const ids = req.query.ids.join()
const ids = req.query.ids
console.log("ids "+ids)
console.log(oauth_access_token, oauth_access_token_secret)
const response = await oauth.sendRequest({
method: 'get',
url: `https://api.twitter.com/2/users?ids=${ids}`,
oauth_access_token,
oauth_access_token_secret
})
console,log(response)
res.json({message: 'ok'})
} catch (error) {
console.log(error)
}
})
The library that I used to send the request to twitter (taking care of headers etc) is https://github.com/ciaranj/node-oauth/blob/a7f8a1e21c362eb4ed2039431fb9ac2ae749f26a/lib/oauth.js#L486, so the oauth in my server.js is a wrapper of that library etc.
I have this Javascript code that generates a token to access the Apple Store api. But when I try to use the token I get "401: Unauthorized access" code. I'm not sure if the code I'm using correct or maybe it might be an issue with the id and key I'm using.
console.log("🏃 appStoreConnectAPIFromNode.js running 🏃")
const fs = require('fs');
const jwt = require('jsonwebtoken'); // npm i jsonwebtoken
// You get privateKey, apiKeyId and issuerId from your Apple App Store Connect account
const privateKey = fs.readFileSync("./AuthKey-12345678.p8") // this is the file you can only download once and should treat like a real, very precious key.
const apiKeyId = "12345678"
const issuerId = "issuerId"
let now = Math.round((new Date()).getTime() / 1000); // Notice the /1000
let nowPlus20 = now + 1199 // 1200 === 20 minutes
let payload = {
"iss": issuerId,
"exp": nowPlus20,
"aud": "appstoreconnect-v1"
}
let signOptions = {
"algorithm": "ES256", // you must use this algorithm, not jsonwebtoken's default
header : {
"alg": "ES256",
"kid": apiKeyId,
"typ": "JWT"
}
};
let token = jwt.sign(payload, privateKey, signOptions);
console.log('#token: ', token);
fs.writeFile('Output.txt', token, (err) => {
// In case of a error throw err.
if (err) throw err;
})
// Congrats! the token printed can now be tested with the curl command below
// curl -v https://api.appstoreconnect.apple.com/v1/apps --Header "Authorization: Bearer <YOUR TOKEN>"
// (no '<>' in the curl command)
I am having an issue with my google APi using a JWT token, I have been having trouble impersonating users for checking calendar avaliability, and I started back tracing and found when I output the JWT token after an authorize, I get the following:
{ access_token: '****',
token_type: 'Bearer',
expiry_date: 1589294984000,
id_token: undefined,
refresh_token: 'jwt-placeholder' }
the id_token comes back undefined. I have set up everything in my cloud services and I call the authorization with a config file
var googleAuthorization = require('../config/calendarConfig.js').jwtClient;
const {google} = require('googleapis');
const calendar = google.calendar('v3');
googleAuthorization.authorize(function(err, token) {
if(err) {
reject(console.log({status: 1, message: 'Google Authorization Failed: ' + err}));
} else {
console.log(token);
}
});
and the config file:
var google = require('googleapis');
var googleAauth = require('google-auth-library');
var scopes = ['https://www.googleapis.com/auth/calendar',
'https://www.googleapis.com/auth/admin.directory.user'];
var key = require('./intranet-google-service-account.json');
var jwtClient = new google.google.auth.JWT(key.client_email, null, key.private_key, scopes,
"service#accountemail.com");
exports.jwtClient = jwtClient;
Can anyone see what I might be doing wrong to not get an ID token back?
I have this function on the express side:
// Register user login
exports.register_user = function(req, res) {
var portalID = req.body.portalID;
var companyName = req.body.companyName;
var password = req.body.password;
var password2 = req.body.password2;
var salt = bcrypt.genSaltSync(12);
var hash = bcrypt.hashSync(password, salt);
password = hash;
var params = {
TableName: "HouseAccounts",
Item: {
"portalID": portalID,
"companyName": companyName,
"points": 0,
"password": password,
}
}
res.sendStatus(200);
}
And this fetch on the front end:
function register() {
fetch("MyURL/register", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
"portalID": document.getElementById("portal-id").value,
"companyName": document.getElementById("company-name").value,
"password": document.getElementById("password").value,
"password2": document.getElementById("password2").value
})
}).then(function(response){console.log(response)});
}
On the express side I can receive the JSON that was sent through the POST and do stuff with that data. However, on my front end I am not receiving a response back from the express side. The connection times out and status is (failed) with error Uncaught (in promise) TypeError: Failed to fetch in the console.
Okay, the problem was I am working on AWS Cloud9 and my Public IP to access the API changed upon restarting the instance so the request was not reaching the server side at all.
I have a problem with implementing an Oauth2 authentication in node.js application where I need to add one extra parameter in the authorization request, but the module simply ignores the "unknown" parameters.
My code is attached below. The parameter being ignored is APIName.
var OAuth2Strategy = require('passport-oauth2').Strategy;
// load the auth variables
var configAuth = require('./auth');
module.exports = function(passport) {
passport.use('ihealth', new OAuth2Strategy({
authorizationURL: 'https://api.ihealthlabs.com:8443/OpenApiV2/OAuthv2/userauthorization/',
tokenURL: 'https://api.ihealthlabs.com:8443/OpenApiV2/OAuthv2/userauthorization/',
clientID: configAuth.iHealthAuth.clientID,
clientSecret: configAuth.iHealthAuth.clientSecret,
callbackURL: configAuth.iHealthAuth.callbackURL,
APIName : 'OpenApiActivity'
},
function(token, refreshToken, profile, done) {
// ...
}
));
};
The reason that I know APIName is being ignored, is that I see the URL in the browser:
https://api.ihealthlabs.com:8443/OpenApiV2/OAuthv2/userauthorization/?response_type=code&redirect_uri=SOMEREDIRECTURI&client_id=SOMECLIENTID
I am wondering how to enable adding extra parameters to the authorization request? Maybe by overriding the function OAuth2Strategy.prototype.authorizationParams in node_modules/passport_oauth2/lib/strategy.js, which looks like this in the donwloaded file:
/**
* Return extra parameters to be included in the authorization request.
*
* Some OAuth 2.0 providers allow additional, non-standard parameters to be
* included when requesting authorization. Since these parameters are not
* standardized by the OAuth 2.0 specification, OAuth 2.0-based authentication
* strategies can overrride this function in order to populate these parameters
* as required by the provider.
*
* #param {Object} options
* #return {Object}
* #api protected
*/
OAuth2Strategy.prototype.authorizationParams = function(options) {
return {};
};
You can override OAuth2Strategy.prototype.authorizationParams as follows
var myStrategy = new OAuth2Strategy({
authorizationURL: 'https://api.ihealthlabs.com:8443/OpenApiV2/OAuthv2/userauthorization/',
tokenURL: 'https://api.ihealthlabs.com:8443/OpenApiV2/OAuthv2/userauthorization/',
clientID: configAuth.iHealthAuth.clientID,
clientSecret: configAuth.iHealthAuth.clientSecret,
callbackURL: configAuth.iHealthAuth.callbackURL
},
function(token, refreshToken, profile, done) {
// ...
});
myStrategy.authorizationParams = function(options) {
return {
APIName : 'OpenApiActivity'
};
};
passport.use('ihealth',myStrategy);
For Microsoft ADFS OAuth 2, this can be used to add the required source parameter; if one wants the callback to include some specific value too, then add the state parameter.
The options in function(options) can be set when calling passport.authenticate:
router.get('/auth', passport.authenticate('ihealth', {time: Date.now()}));
In this time I managed to find a workaround. Maybe it will help someone with a similar problem.
For the solution I didn't use the well known modules such as passport-oauth2 or simple-oauth2, but just the modules querystring for building the request URL and the module request for making the HTTP calls.
Example:
var express = require('express');
var router = express.Router();
var request = require('request');
var qs = require('querystring');
var configAuth = require('../config/auth');
var authorization_url_site = configAuth.iHealthAuth.authorizationSite;
var authorization_url_params = {
response_type : 'code',
client_id: configAuth.iHealthAuth.clientID,
redirect_uri: configAuth.iHealthAuth.callbackURL,
APIName : configAuth.iHealthAuth.APIName
};
var authorization_uri = authorization_url_site + '?' + qs.stringify(authorization_url_params);
var token_url_site = configAuth.iHealthAuth.tokenSite;
var token_url_params = {
grant_type : 'authorization_code',
client_id: configAuth.iHealthAuth.clientID,
client_secret: configAuth.iHealthAuth.clientSecret,
redirect_uri: configAuth.iHealthAuth.callbackURL,
code: req.query.code
};
var token_uri = token_url_site + '?' + qs.stringify(token_url_params);
// Initial page redirecting to the login page
router.route('/auth')
.get(function (req, res) {
res.redirect(authorization_uri);
});
// Callback service parsing the authorization token and asking for the access token
router.route('/')
.get(function(req, res) {
request(token_uri, function(err, response, body) {
if(err) {
throw err;
} else {
var data = JSON.parse(body);
// save token to database or file
saveToken(data);
}
});
});
});
module.exports = router;