You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-30 04:23:07 +03:00
OIDC: validate id token (#3531)
* validate id token * comments * tidy comments
This commit is contained in:
@ -14,11 +14,20 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { mocked } from "jest-mock";
|
||||
import jwtDecode from "jwt-decode";
|
||||
|
||||
import { M_AUTHENTICATION } from "../../../src";
|
||||
import { logger } from "../../../src/logger";
|
||||
import { validateOIDCIssuerWellKnown, validateWellKnownAuthentication } from "../../../src/oidc/validate";
|
||||
import {
|
||||
validateIdToken,
|
||||
validateOIDCIssuerWellKnown,
|
||||
validateWellKnownAuthentication,
|
||||
} from "../../../src/oidc/validate";
|
||||
import { OidcError } from "../../../src/oidc/error";
|
||||
|
||||
jest.mock("jwt-decode");
|
||||
|
||||
describe("validateWellKnownAuthentication()", () => {
|
||||
const baseWk = {
|
||||
"m.homeserver": {
|
||||
@ -194,3 +203,96 @@ describe("validateOIDCIssuerWellKnown", () => {
|
||||
expect(() => validateOIDCIssuerWellKnown(wk)).toThrow(OidcError.OpSupport);
|
||||
});
|
||||
});
|
||||
|
||||
describe("validateIdToken()", () => {
|
||||
const nonce = "test-nonce";
|
||||
const issuer = "https://auth.org/issuer";
|
||||
const clientId = "test-client-id";
|
||||
const idToken = "test-id-token";
|
||||
|
||||
const validDecodedIdToken = {
|
||||
// nonce matches
|
||||
nonce,
|
||||
// not expired
|
||||
exp: Date.now() / 1000 + 5555,
|
||||
// audience is this client
|
||||
aud: clientId,
|
||||
// issuer matches
|
||||
iss: issuer,
|
||||
};
|
||||
beforeEach(() => {
|
||||
mocked(jwtDecode).mockClear().mockReturnValue(validDecodedIdToken);
|
||||
|
||||
jest.spyOn(logger, "error").mockClear();
|
||||
});
|
||||
|
||||
it("should throw when idToken is falsy", () => {
|
||||
expect(() => validateIdToken(undefined, issuer, clientId, nonce)).toThrow(new Error(OidcError.InvalidIdToken));
|
||||
});
|
||||
|
||||
it("should throw when idToken cannot be decoded", () => {
|
||||
mocked(jwtDecode).mockImplementation(() => {
|
||||
throw new Error("oh no!");
|
||||
});
|
||||
expect(() => validateIdToken(undefined, issuer, clientId, nonce)).toThrow(new Error(OidcError.InvalidIdToken));
|
||||
});
|
||||
|
||||
it("should throw when issuer does not match", () => {
|
||||
mocked(jwtDecode).mockReturnValue({
|
||||
...validDecodedIdToken,
|
||||
iss: "https://badissuer.com",
|
||||
});
|
||||
expect(() => validateIdToken(idToken, issuer, clientId, nonce)).toThrow(new Error(OidcError.InvalidIdToken));
|
||||
expect(logger.error).toHaveBeenCalledWith("Invalid ID token", new Error("Invalid issuer"));
|
||||
});
|
||||
|
||||
it("should throw when audience does not include clientId", () => {
|
||||
mocked(jwtDecode).mockReturnValue({
|
||||
...validDecodedIdToken,
|
||||
aud: "qwerty,uiop,asdf",
|
||||
});
|
||||
expect(() => validateIdToken(idToken, issuer, clientId, nonce)).toThrow(new Error(OidcError.InvalidIdToken));
|
||||
expect(logger.error).toHaveBeenCalledWith("Invalid ID token", new Error("Invalid audience"));
|
||||
});
|
||||
|
||||
it("should throw when audience includes clientId and other audiences", () => {
|
||||
mocked(jwtDecode).mockReturnValue({
|
||||
...validDecodedIdToken,
|
||||
aud: `${clientId},uiop,asdf`,
|
||||
});
|
||||
expect(() => validateIdToken(idToken, issuer, clientId, nonce)).toThrow(new Error(OidcError.InvalidIdToken));
|
||||
expect(logger.error).toHaveBeenCalledWith("Invalid ID token", new Error("Invalid audience"));
|
||||
});
|
||||
|
||||
it("should throw when nonce does not match", () => {
|
||||
mocked(jwtDecode).mockReturnValue({
|
||||
...validDecodedIdToken,
|
||||
nonce: "something else",
|
||||
});
|
||||
expect(() => validateIdToken(idToken, issuer, clientId, nonce)).toThrow(new Error(OidcError.InvalidIdToken));
|
||||
expect(logger.error).toHaveBeenCalledWith("Invalid ID token", new Error("Invalid nonce"));
|
||||
});
|
||||
|
||||
it("should throw when token does not have an expiry", () => {
|
||||
mocked(jwtDecode).mockReturnValue({
|
||||
...validDecodedIdToken,
|
||||
exp: undefined,
|
||||
});
|
||||
expect(() => validateIdToken(idToken, issuer, clientId, nonce)).toThrow(new Error(OidcError.InvalidIdToken));
|
||||
expect(logger.error).toHaveBeenCalledWith("Invalid ID token", new Error("Invalid expiry"));
|
||||
});
|
||||
|
||||
it("should throw when token is expired", () => {
|
||||
mocked(jwtDecode).mockReturnValue({
|
||||
...validDecodedIdToken,
|
||||
// expired in the past
|
||||
exp: Date.now() / 1000 - 777,
|
||||
});
|
||||
expect(() => validateIdToken(idToken, issuer, clientId, nonce)).toThrow(new Error(OidcError.InvalidIdToken));
|
||||
expect(logger.error).toHaveBeenCalledWith("Invalid ID token", new Error("Invalid expiry"));
|
||||
});
|
||||
|
||||
it("should not throw for a valid id token", () => {
|
||||
expect(() => validateIdToken(idToken, issuer, clientId, nonce)).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user