I have a loopback 4
project and I am using @loopback/authentication: ^6.0.0
to add JWT authentication. I followed the official documentaion and I wired it up to my MongoDB. All of this went well and I can secure endpoints. However, progress has come to screeching halt. When a user logs in the system generates a JWT token and I need to add a userId
to the payload. I just can't figure out how to add anything to the payload.
The code that creates the JWT at login is:
@post('/users/login', {
responses: {
'200': {
description: 'Token',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
token: {
type: 'string',
},
},
},
},
},
},
},
})
async login(
@requestBody(CredentialsRequestBody) credentials: Credentials,
): Promise<{token: string}> {
// ensure the user exists, and the password is correct
const user = await this.userService.verifyCredentials(credentials);
// convert a User object into a UserProfile object (reduced set of properties)
const userProfile = this.userService.convertToUserProfile(user);
// create a JSON Web Token based on the user profile
const token = await this.jwtService.generateToken(userProfile);
return {token};
}
I first tried to manually add userId
from the user object to the userProfile object and that didn't work. When I check the generateToken
method I find it is typed to UserProfile
which is defined as:
export interface UserProfile extends Principal {
email?: string;
name?: string;
}
Just to test I tried to add my userID: number;
parameter but that doesn't work. The payload generated is always:
{
"id": "84f0106e-3d47-4af5-8ea3-f8d41194be87",
"name": "chrisloughnane",
"email": "test@gmail.com",
"iat": 1597973078,
"exp": 1597994678
}
The name
parameter is also confusing because I do not that a name
in my User
object definition. It does have a username
, how does it bind this, I can't find the code.
How can I add extra parameters to the generate JWT payload?
Curious
When a request is made to a secured endpoint this payload is then processed so the userId
is used to fetch the correct data. I can write a function to manually decode the payload, is there a built in function to do this?
UPDATE: The solution to access the payload I came up with was to inject SecurityBindings.USER
to the constructor of my controller and then assign it to a variable that can be used in any endpoint.
constructor(
@repository(IconsRepository)
public iconsRepository: IconsRepository,
@inject(SecurityBindings.USER, {optional: true})
public user: UserProfile,
) {
this.userId = this.user[securityId];
}