verify() function
wz2b opened this issue · 5 comments
This is more of a typescript question than anything, but I encountered this in aws-jwt-verify and I want to understand what it means when you declare a method parameter as ...[a, b]: SomeType
I'm also not entirely sure why this method is generic - what is the purpose of the type parameter T?
Would somebody mind pointing me toward some documentation? I have been searching, but those are hard search terms and I don't even know what to call this thing. Thanks.
/**
* Verify (asynchronously) a JWT that is signed by Amazon Cognito.
* This call is asynchronous, and the JWKS will be fetched from the JWKS uri,
* in case it is not yet available in the cache.
*
* @param jwt The JWT, as string
* @param props Verification properties
* @returns Promise that resolves to the payload of the JWT––if the JWT is valid, otherwise the promise rejects
*/
verify<T extends SpecificVerifyProperties>(...[jwt, properties]: CognitoVerifyParameters<SpecificVerifyProperties>):
Promise<CognitoIdOrAccessTokenPayload<IssuerConfig, T>>;
Extending that question, am I close here? And do my names for these types make any sense?
/*
* Declare extra things I want, some that are part of the standard claims,
* others that are custom
*/
interface ExtraClaims {
email: string,
/* The actual custom property shoes up as custom:customer - is this right? */
"custom:customer": string
}
type TokenPayload = CognitoIdOrAccessTokenPayload<CognitoJwtVerifierMultiProperties, ExtraClaims>;
/*
* getVerifiedToken() - takes a token, verifies it, and returns the decoded contents
* asynchronously
*/
async function getVerifiedToken(token: string): Promise<TokenPayload> {
const verifier = CognitoJwtVerifier.create<CognitoJwtVerifierMultiProperties>({
userPoolId: "<user_pool_id>",
tokenUse: "id",
clientId: null /* don't care? */
});
return verifier.verify(token)
.then((data: TokenPayload) => {
console.log("User is", data.username);
console.log("His e-mail is", data.email);
console.log("Groups this person is in", data.groups);
return data;
})
.catch(error => {
console.log("Token could not be verified", error);
return Promise.reject("Nope");
})
}
Here's some background first.
This lib uses some TypeScript magic (/shenanigans) to a.o. alert users to properly supply the required verification properties either at verifier level upon calling create
, or later upon calling verify
.
Notably, if you create
the verifier without specifying e.g. clientId
the TypeScript types will enforce that you must then provide clientId
upon calling verify
.
Example. If you provide all such parameters while calling create
you can later just call verify
with just the JWT:
const verifier = CognitoJwtVerifier.create({userPoolId: "xxx", clientId: "yyy", tokenUse: "access"})
verifier.verify("ey....") // just 1 parameter needed, the JWT
But if you did not provide e.g. the clientId
while calling create:
const verifier = CognitoJwtVerifier.create({userPoolId: "yours", tokenUse: "access"}) // clientId not provided yet
verifier.verify("ey....", { clientId: "yours" }) // 2nd parameter is required now, or it won't compile
The intent of this is to help developers be explicit, and make it hard to do insecure things––such as not checking clientId
. You should check that, unless you're quite sure you don't.
(If I'm very honest I'm no longer sure that this TypeScript magic is worth it. The explicitness it enforces is nice but it leads to impenetrable source code. But here you have it, this was the rationale of it all.)
Now to some concrete answers.
This is more of a typescript question than anything, but I encountered this in aws-jwt-verify and I want to understand what it means when you declare a method parameter as ...[a, b]: SomeType
I'm also not entirely sure why this method is generic - what is the purpose of the type parameter T?
The magic explained above works using this generic. The type of the parameters to verify
depend on the type of the parameters that you provided to create
. We use a generic to make this happen.
Extending that question, am I close here?
I'm not sure all the explicit typings you're putting in are helping you. You should be able to just call create
without providing any generic type as TypeScript will infer it from your parameters.
If you just wanna check an extra claim that you put on the JWT, you can just do so, this compiles:
import { CognitoJwtVerifier } from "aws-jwt-verify";
const verifier = CognitoJwtVerifier.create({
userPoolId: "xxx",
clientId: "yyy",
tokenUse: "access",
});
verifier
.verify("ey...")
.then((payload) => payload["custom:customer"] === "CustomerID"); // this field is of type Json
Otherwise use a cast:
verifier
.verify("ey...")
.then((payload) => acceptOnlyString(payload["custom:customer"] as string));
function acceptOnlyString(s: string) {
return s;
}
We should document all of this. Might you be interested in submitting a PR ...
Did that help @wz2b ?
YES! Very much! And I am glad you pinged me about this again because for some reason I missed the notification that you responded 9 days ago. Sorry about that, but thank you!!!
I don't feel expert enough to add documentation and submit a PR yet, but let me get all this working and then I'll think about it!