Testing Cognito JWKS using mock-jwk? - node.js

Auth AWS lambda
export const authorizeFinance = async (event) => {
if (event.headers.authorization) {
const token = event.headers.authorization.substring(7);
try {
const verifier = CognitoJwtVerifier.create({
userPoolId: "xyz",
tokenUse: "access",
clientId: "123",
});
const payload = await verifier.verify(token);
if (authLogic(payload)) {
return {isAuthorized: true, context: {AuthInfo: 'Finance'}}
}
return {isAuthorized: false, context: {}}
} catch (e) {
return {isAuthorized: false, context: {}}
}
}
}
Test case in jest using mock-jwks
import createJWKSMock from "mock-jwks";
import {authorizeFinance} from "#functions/auth-finance/handler";
describe('Authenticate finance', () => {
const jwks = createJWKSMock('https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-xyz.', 'well-known/jwks.json');
beforeEach(() => {
jwks.start();
});
afterEach(() => {
jwks.stop();
});
test('should verify the token', async () => {
const token = jwks.token({
aud: 'https://test.auth-domain.com/',
iss: 'https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-xyz',
});
console.log(token);
const event = {
headers: {
authorization: `Bearer ${token}`,
}
};
jest.unmock('axios');
const basicResponse = await authorizeFinance(event);
console.log('jatin', basicResponse);
expect(basicResponse).toEqual({ isAuthorized: false, context: {} });
});
})
Fails
Authentication failed JWK for kid "BlYCji0Uj6V3LAxmK1JHqYgnPJIUUqeiS8YzUf0vfh0=" not found in the JWKS
Authentication failed Missing Token use. Expected one of: id, access

Related

JsonWebTokenError: secretOrPublicKey must be an asymmetric key when using RS256

I have the below codes using #types/google-one-tap library in Angular 14 project:
// #ts-ignore
window.onGoogleLibraryLoad = () => {
// #ts-ignore
google.accounts.id.initialize({
client_id: '85464xxxxxx-xxxx.apps.googleusercontent.com',
callback: this.handleCredentialResponse.bind(this),
auto_select: false,
cancel_on_tap_outside: true
});
// #ts-ignore
google.accounts.id.renderButton(
// #ts-ignore
document.getElementById("buttonDiv"),
{ theme: "outline", size: "large", width: "100%" }
);
// #ts-ignore
google.accounts.id.prompt((notification: PromptMomentNotification) => { });
};
}
async handleCredentialResponse(response: CredentialResponse) {
console.warn('this was called')
await this.service.LoginWithGoogle(response.credential).subscribe(
(x: any) => {
console.warn(x, 'this is from the authentication google')
localStorage.setItem("token", x.token);
this._ngZone.run(() => {
this.router.navigate(['/logout']);
})
},
(error: any) => {
console.log(error);
}
);
}
Then this calles the auth service below still in my Angular app:
LoginWithGoogle(credentials: string): Observable<any> {
const header = new HttpHeaders().set('Content-type', 'application/json');
return this.httpClient.post(this.path + "/loginwithgoogle", JSON.stringify({ token: credentials }), { headers: header });
}
}
Then in my server - node.js, I have the below implementation to verify the token:
app.post('/loginwithgoogle', function (req, response) {
console.warn(req.body.token);
const PRIVATE_KEY = 'xxxxx-xxxxxxxxxxx';
console.warn('api called')
const decode = jwt.verify(req.body.token, PRIVATE_KEY.replace(/\\n/g, '\n'), { algorithms: ['RS256'] });
response.json({
login: true,
data: decode
});
});
Upon calling the api, I get the below error:
JsonWebTokenError: secretOrPublicKey must be an asymmetric key when using RS256
Any Idea what I might be missing out?

Set timeout Function on inactivity of user in React JS

I have created login form in reactjs. This stores a token in state. Login and Logout functions are working properly. But I want to expire this token on inactivity of the user and user will automatically logout.
Login:
export const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
setLogin: (state, action) => {
state.user = action.payload.user;
state.token = action.payload.token;
},
setLogout: (state) => {
state.user = null;
state.token = null;
}
},
});
const login = async (values, onSubmitProps) => {
const loggedInResponse = await fetch("http://localhost:5001/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(values),
});
const loggedIn = await loggedInResponse.json();
onSubmitProps.resetForm();
if (loggedIn) {
dispatch(
setLogin({
user: loggedIn.user,
token: loggedIn.token,
})
);
navigate("/dashboard");
}
};
const handleFormSubmit = async (values, onSubmitProps) => {
if (isLogin) await login(values, onSubmitProps);
};

Context is empty in GraphQL middleware

I'm sending from frontend authorization token in headers and then I want to check validity of this token in some endpoints using middleware and context, but context is always empty.
I'm using type-graphql.
Frontend code (I check request in 'Network' tab and I can see my additional header):
private async mutate<T>(
mutation: DocumentNode,
data: unknown,
token?: string
) {
const response = await apolloClient.mutate<T>({
mutation: mutation,
context: {
headers: {
'auth-token': token || '',
},
},
variables: {
data: data,
},
});
return response.data;
}
Resolver code:
#Mutation(() => Token)
#UseMiddleware(authMiddleware)
async login(#Ctx() ctx: unknown, #Arg('data') data: LoginInput) {
console.log(ctx);
...
}
Middleware code:
export const authMiddleware: MiddlewareFn = ({ context }, next) => {
console.log(context);
try {
return next();
} catch (error) {
return next();
}
};
console.log is always equal to {}
I found the cause.
In declaration of ApollorServer the context was missing.
const server = new ApolloServer({
schema,
context: ({ req }) => {
const context = {
req,
};
return context;
},
cors: {
origin: '*',
credentials: true,
},
});

I get undefined when reading my response but there is a response in React.js

I can't figure it out, the answer comes in the network table but when I want to console.log it, this will display undefined. Do you have any idea why? I attach the pictures and the code.
Here is a image with my codes and response
Here is the code - first one is where I send the response. As I said, it's going well on network tab, I get a 200 status.
export const getAccountStatus = async (req, res) => {
const user = await User.findById(req.user._id).exec();
const account = await stripe.accounts.retrieve(user.stripe_account_id);
// console.log("user account retrieve", account);
const updatedUser = await User.findByIdAndUpdate(
user._id,
{
stripe_seller: account
},
{ new: true }
)
.select("-password")
.exec();
console.log(updatedUser);
res.send(updatedUser);
};
Here is the page where i want to console.log it:
const StripeCallback = ({ history }) => {
const { auth } = useSelector(state => ({ ...state }));
const dispatch = useDispatch();
useEffect(() => {
if (auth && auth.token) accountStatus();
}, [auth]);
const accountStatus = async () => {
try {
const res = await getAccountStatus(auth.token);
console.log(res);
} catch (err) {
console.log(err);
}
};
return <div>test</div>;
};
Ang here is the Axios.post (which is working well as I know):
export const getAccountStatus = async token => {
await axios.post(
`${process.env.REACT_APP_API}/get-account-status`,
{},
{
headers: {
Authorization: `Bearer ${token}`
}
}
);
};
Thank you!
getAccountStatus doesn't have a return statement, so res in const res = await getAccountStatus(auth.token); will always be undefined.
export const getAccountStatus = async token => {
return axios.post( // <----- added return
`${process.env.REACT_APP_API}/get-account-status`,
{},
{
headers: {
Authorization: `Bearer ${token}`
}
}
);
};

nuxtjs apollo-client does not set authorization header

I am trying to create a login functionality using nuxtjs with the nuxtjs apollo-module and nodejs in the backend using apollo-server. I would like to pass the token from the frontend (nuxtjs/apollo-client) to the backend (nodejs/apollo-server).
Signin Function (frontend)
async signin () {
const email = this.email
const password = this.password
try {
const res = await this.$apollo.mutate({
mutation: signIn,
variables: {
email,
password
}
}).then(({ data }) => data && data.signIn)
const token = res.token
await this.$apolloHelpers.onLogin(token)
this.$router.push('/feed')
} catch (err) {
// Error message
}
}
nuxtjs.config (frontend)
apollo: {
clientConfigs: {
default: {
httpEndpoint: 'http://localhost:8000/graphql',
wsEndpoint: 'ws://localhost:8000/graphql',
authenticationType: 'Bearer',
httpLinkOptions: {
credentials: 'include'
},
}
}
Cookie in Browser DevTools
Index File (backend)
const app = express()
const corsConfig = {
origin: 'http://127.0.0.1:3000',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
credentials: true
}
app.use(cors(corsConfig))
app.use(morgan('dev'))
const getMe = async req => {
const token = req.headers.authorization // <========
console.log(token) // returns 'Bearer undefined'
if (token) {
try {
return await jwt.verify(token, process.env.SECRET)
} catch (e) {
// Error message
}
}
}
const server = new ApolloServer({
introspection: true,
playground: true,
typeDefs: schema,
resolvers,
context: async ({ req }) => {
if (req) {
const me = await getMe(req)
return {
models,
me,
secret: process.env.SECRET,
loaders: {
user: new DataLoader(keys =>
loaders.user.batchUsers(keys, models),
),
},
}
}
},
})
server.applyMiddleware({
app,
path: '/graphql',
cors: false
})
const httpServer = http.createServer(app)
server.installSubscriptionHandlers(httpServer)
const port = process.env.PORT || 8000
sequelize.sync({ force: true }).then(async () => {
createUsers(new Date())
httpServer.listen({ port }, () => {
console.log(`Apollo Server on http://localhost:${port}/graphql`)
})
})
The token is saved in a cookie called 'apollo-token'. However the Authoriation header in the format 'Bearer token' is not set. According to the apollo-client documentation this should be set automatically (https://github.com/nuxt-community/apollo-module#authenticationtype-string-optional-default-bearer).
What am I missing? I would be very thankful for any kind of help!

Resources