Why does Hapi bomb when creating cookies? - hapi

Setting a simple cookie with Hapi.
return h.redirect('http://localhost:3000/handle-login').state('tester', { authToken, refreshToken })
It breaks.
Error: Invalid cookie value: [object Object]
at exports.Definitions.internals.Definitions.internals.Definitions.format...
refreshToken and authToken are just strings.
Seems this is a common issue with Hapi
https://github.com/hapijs/hapi/issues?utf8=%E2%9C%93&q=%22Invalid+cookie+value%22
But no real solutions other than disabling some error configs in the server (sounds like a bad idea to me)
How can I make Hapi happy with simple cookie handling?

If you are storing a cookie as a JSON, you need to set the encoding attribute when you configure the server:
server.state('tester', {
ttl: null,
isSecure: true,
isHttpOnly: true,
encoding: 'base64json',
clearInvalid: true,
strictHeader: true
});

Related

sendSignInLinkToEmail with Flutter, Firebase Auth throws error "[firebase_auth/missing-continue-uri] A continue URL must be provided in the request."

Here's my code. I'm attempting to implement Firebase Passwordless Sign in.
final ActionCodeSettings acs = ActionCodeSettings(
url: 'https://example.com/completeLogin}',
handleCodeInApp: true,
iOSBundleId: config.bundleId,
androidPackageName: config.packageName,
dynamicLinkDomain: config.firebaseDomain,
androidInstallApp: true);
await FirebaseAuth.instance.sendSignInLinkToEmail(
email: 'example#domain.com',
actionCodeSettings: acs);
To solve this,
A valid continue URL must be provided in the request.
Make sure that the URLs you are providing are valid.
Your URL has a } at the end - url: 'https://example.com/completeLogin}', which is probably making it invalid.

axios not sending cookie to nestjs from NextJs

Have a front end nextJs running on a different port to the backend nestjs.
Within the nextJs session-cookie I have 2 JWT tokens access and refresh.
I can extract the access token from the next-auth session-token but axios will not send to nestjs.
If I use the { withCredentials: true } the whole next-auth token is sent but if I use the headers object nothing is received
const data = await axios.post(
process.env.NEXT_PUBLIC_SH_API_BASEURL + '/blog',
{ formData },
//{ withCredentials: true }
{
headers: {
Cookie:
'Authentication=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEzNTQ1N2FiLWI4MGUtNDU2OC1hY2RiLWNiODZmYTJlNGQxMyIsImlhdCI6MTY1MzU0NjM0NiwiZXhwIjoxNjU0NDQ2MzQ2fQ.fvnRXYwheuIOHvlTZRGqBiVR98JxdT7UqZbc6SAvcAk; Path=/; HttpOnly;'
},
}
);
nestJS - log when using with credentials
{
'next-auth.csrf-token': '493deccd24c0165f8afe08db04352415c46c7a6f150f9c51320aea0d5444589d|51953c1c056c986b799afb9dcea8c94469d35b4aab291b02ee343057fa80a70e',
'next-auth.callback-url': 'http://localhost:3000/auth/signin?callbackUrl=http://localhost:3000/',
'next-auth.session-token': 'eyJhbGc
}
But if use the headers I get
[Object: null prototype] {}
The nestJs logging is done using:
jwtFromRequest: ExtractJwt.fromExtractors([
(request: Request) => {
console.log('JWT strategy auth cookie');
console.log(request?.cookies);
return request?.cookies?.Authentication;
},
]),
If I make a call from postman there is no issue with processing the header cookie.
Could you let me know how to get axios to send the header cookie only?
Thanks

jwt acess_token and refresh_token mechanism: axios : How to keep checking for the access_token is working

I am using JWT token based authentication system. i.e djangorestframework-simplejwt in my backend
Now I am using reactj and axios as frontend:
After providing username and pass to the login api, I got access_token and refresh_token which I stored in the localstorage
Now I am trying to connect to an api using access_token.
I get Token invalid or expired
Example I am trying to change password using this api and provide access_token
const url = "dj-rest-auth/password/change/";
const auth = {
headers: {
Authorization: "Bearer " + localStorage.getItem("access_token"),
Accept: "application/json",
"Content-Type": "application/json",
},
};
const data = {
old_password: old_password,
new_password1: new_password1,
new_password2: new_password2,
};
const promise = axios.post(url, data, auth);
promise
.then((res) => {
console.log(res)
})
.catch((err) => {
if (err.response) {
console.log(`${err.response.status} :: ${err.response.statusText}`)
console.log(err.response.data)
}
})
I can do another api call using refresh_token to get access_token when i get an err.
But sometimes, the err can be due to network error or something else. Then even i try to get access_token using refresh_token, it will just get into a loop.
HOw to do this the right way
If you are using Django as the backend, I would suggest using dj-rest-auth for JWT token authentication. dj-rest-auth requires "djangorestframework-simplejwt" for token management.
It is recommended to store access token and refresh token in httponly cookie so that it is not accessed by javascript.
Add JWTtokenAuthentication as authentication classes in settings.py.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'dj_rest_auth.jwt_auth.JWTCookieAuthentication'
]
}
Add the below configuration too in settings.py
REST_SESSION_LOGIN = False
SITE_ID=1
REST_USE_JWT = True
JWT_AUTH_COOKIE = 'access-token' #any name
JWT_AUTH_REFRESH_COOKIE = 'refresh_token' #any name
JWT_AUTH_SECURE = True
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
There is an open issue with dj-rest-auth, that requires the below code to be implemented in your back-end Github issue: https://github.com/iMerica/dj-rest-auth/issues/97. As workaround suggested, you have to create a file middleware.py and paste below code.
import json
from django.utils.deprecation import MiddlewareMixin
from yourapp.settings import JWT_AUTH_REFRESH_COOKIE # from settings.py
class MoveJWTRefreshCookieIntoTheBody(MiddlewareMixin):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
return response
def process_view(self, request, view_func, *view_args, **view_kwargs):
if request.path == '/token/refresh/' and JWT_AUTH_REFRESH_COOKIE in request.COOKIES:
if request.body != b'':
data = json.loads(request.body)
data['refresh'] = request.COOKIES[JWT_AUTH_REFRESH_COOKIE]
request._body = json.dumps(data).encode('utf-8')
else:
print("The incoming request body must be set to an empty object.")
return None
By now, your back-end will be successfully generating access token and refresh token. Even your back-end will be capable of refreshing access token using refresh token.
Front-End:
By default, access token and refresh tokens are stored in httponly cookie, so you don't need to worry about that part.
Axios can be used to make call to login-end point to get tokens. Make sure you use "withCredentials" and "Headers" in your request.
Response will be tokens, by default it will be stored in httponly cookie, since we are using dj-rest-auth. For all the consecutive requests, httponly cookie will be included, if tokens are valid, user will be provided access. IF token is expired, you need to make call to refresh endpoint to get new access token.
Since you are in development mode, you have to have same domain for both BE and FE, different ports.You can start django-server using below command and make sure your FE is also running in localhost
python manage.py runserver localhost:8080
dj-rest-auth : https://dj-rest-auth.readthedocs.io/en/latest/index.html

IBM Watson Speech-to-Text speech-javascript-sdk "HTTP Authentication failed; no valid credentials available"

I'm trying to set up IBM Watson Speech-to-Text to run in my Angular frontend. I'm using German Attanasio's speech-javascript-sdk library. I want the transcript text to go to the console so I'm using the microphone-streaming-object-to-console.html example. Here's my code:
const options = {
token: $scope.token,
model: 'en-US_BroadbandModel',
word_confidence: true,
object_mode: true
};
var stream = WatsonSpeech.SpeechToText.recognizeMicrophone(options);
The error I'm getting is
watson-speech.js:10482 WebSocket connection to 'wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize?model=en-US_BroadbandModel&watson-token=[object%20Object]' failed: HTTP Authentication failed; no valid credentials available
My guess is that my token isn't in the right format. The IAM bearer token is provided as a JSON object:
{
access_token: "eyJraWQiOiIyMDIwMDIyNTE4MjgiLCJhbGciOiJSUzI1NiJ9.e…",
expiration: 1585264266,
expires_in: 3600,
refresh_token: "OKA5toCaoVmYsPbwpjARE1971xspAe7Xg5nOm9pRrLKjKgaubr…",
scope: "ibm openid",
}
I tried providing the bare naked access_token, and I tried providing the JSON object. Both resulted in the same error message. Which format is correct?
Did I set up the options object correctly? Is it object_mode orobjectMode?
I don't understand what Object.assign(token, means in the example code.
I had the same problem and I found the solution working perfectly:
In 'options' constant you need to change the field 'token' by 'accessToken' and It should be works.
NOTE:
The field 'model' in 'options' has a default value, but if you want to change it you have to set value to 'model' and 'laguage',
const params = {
accessToken: 'token'
format: true,
extractResults: true,
objectMode: true,
model:'es-MX_BroadbandModel',
laguage: 'es-MX'
};

Passport and SailsJS, how to get isAuthenticated() test to pass

My code keeps failing here when the user tries to login:
isAuthenticated: function (req, res) {
if (req.isAuthenticated()) { return res.json(req.user); }
else { return res.send(401); }
},
It FAILS and I get GET http://localhost:1337/user/authenticated 401 (Unauthorized) in the console, even though the user has entered in a correct email and password.
Where in the code makes that test pass?
I have the related StackOverflow question with more info HERE.
The problem was that my frontend application has a different origin than my backend application, so the AJAX requests will not include the session cookie and req.isAuthenticated() will never return true.
Use the withCredentials options to force it.
$http({ withCredentials: true, ... })