UNPKG

keycloak-verify

Version:

Javascript backend library to verify keycloak tokens and get user info

117 lines (106 loc) 4.28 kB
import { pick } from "ramda"; import axios from "axios"; import jwkToPem from "jwk-to-pem"; import { sign } from "jsonwebtoken"; import Keycloak from ".."; const kid = "2f51904a-442f-4549-af93-0d0a2ab34129"; const keyPair = { publicJWK: { keys: [ { alg: "RS256", kty: "RSA", e: "AQAB", kid, n: "f40P5FlkgD1_6BLAHF40dqGef3hskekkjbdLggxcXNZiWkJI6XQ4n-mQut5DcjADzTojCzT8CNIfje4lXoBDmLAUNtaOhh8FbWfUuXHhjqGMUMAWUXW36TC8RMbFQ8S-NxUKchJP-DDnC5hzMahDjtHOa8Qz9I_uEOoezdzPOBE" } ] }, privatePEM: "-----BEGIN RSA PRIVATE KEY-----\n\ MIICWgIBAAKBgH+ND+RZZIA9f+gSwBxeNHahnn94bJHpJI23S4IMXFzWYlpCSOl0\n\ OJ/pkLreQ3IwA806Iws0/AjSH43uJV6AQ5iwFDbWjoYfBW1n1Llx4Y6hjFDAFlF1\n\ t+kwvETGxUPEvjcVCnIST/gw5wuYczGoQ47RzmvEM/SP7hDqHs3czzgRAgMBAAEC\n\ fytYxQ3VU1JBlDZKKP97BFlMk5C+XCc6FDIVGJQZn0ntkX8bB6xO0u+FcKoQ3trv\n\ dltIZqBoYT6eKhsR06FJ9a5xCQfgAqIhAE2qfkLESuzIPJvL7fUl4WJxecf79EiG\n\ a0nwk2j00y02FizgSPPYjrJWMSCiQfg0GVDU57vzZxECQQDbPQJZAI30uoNIt98N\n\ NvM/xe6sDzUUJuW+dli1B/WXlx0DqD5DxzNYt9mcS7vsBs0YtyPCXa8Ix4O+53iT\n\ 7KI9AkEAlPBMS2kpx1J4V56KLhKArc4PltuyONkCfnRXlu6KjyHDrbxkQ4tR+rhb\n\ Sj+BHshm0PWMMroDb2izoERheoFuZQJBAKNh7AX369KdzIi8vnVSpiS4lQ2Up7HE\n\ 6yHtgF4o+FVoQC8hioVoRlOvb3SS3BEhYGcy1Gtc9bxNM1lplupmRuECQDy4EoKT\n\ 5wJprsIZ0j+iL2+sGFLqUig24HtpNuRDb52WqE3GBiI7RDqwuhb0+NDx5mi+EmAD\n\ 0a6zwrdN6WemKLkCQQDKhT1ayQCLVbMmO0qfIHMSTPBHIfzHclGURxRk2pjl3LaY\n\ oIcNiLaNvGP9o8/ftYYLr0B7HnGYx7nnz5oiCnln\n\ -----END RSA PRIVATE KEY-----" }; const payload = { sub: "user_id", preferred_username: "user_name", email: "email@email.com", name: "name", nonUserField: "test" }; const options = { algorithm: "RS256", header: { kid }, expiresIn: "1h" }; const token = sign(payload, keyPair.privatePEM, options); jest.mock("axios"); axios.get.mockResolvedValue({ data: keyPair.publicJWK }); describe("Keycloak Verify", () => { describe("verify offline without public key", () => { it("should get UserInfo", async () => { const expectedUser = { id: payload.sub, userName: payload.preferred_username, emailVerified: undefined, resourceAccess: undefined, email: payload.email, name: payload.name }; const config = { realm: "realm", authServerUrl: "url" }; const keycloak = Keycloak(config); const user = await keycloak.verifyOffline(token); expect(pick(['id', 'userName', 'emailVerified', 'resourceAccess', 'email', 'name'], user)).toEqual(expectedUser); }); }); describe("verify offline with public key without cache", () => { it("should get UserInfo", async () => { const expectedUser = { id: payload.sub, userName: payload.preferred_username, emailVerified: undefined, resourceAccess: undefined, email: payload.email, name: payload.name }; const config = { publicKey: jwkToPem(keyPair.publicJWK.keys[0]) }; const keycloak = Keycloak(config); const user = await keycloak.verifyOffline(token); expect(pick(['id', 'userName', 'emailVerified', 'resourceAccess', 'email', 'name'], user)).toEqual(expectedUser); }); it("should not get UserInfo", () => { const config = { publicKey: "FAKE" }; const keycloak = Keycloak(config); return expect(keycloak.verifyOffline(token)).rejects.toThrow(); }); it("should get public key twice", async () => { axios.get.mockClear(); const config = { useCache: false, realm: "realm", authServerUrl: "url" }; const keycloak = Keycloak(config); const user1 = await keycloak.verifyOffline(token); const user2 = await keycloak.verifyOffline(token); expect(user1).toEqual(user2); expect(axios.get.mock.calls.length).toEqual(2); }); }); describe("verify offline without public key with cache", () => { it("should get public key once", async () => { axios.get.mockClear(); const config = { useCache: true, realm: "realm", authServerUrl: "url" }; const keycloak = Keycloak(config); const user1 = await keycloak.verifyOffline(token); const user2 = await keycloak.verifyOffline(token); expect(user1).toEqual(user2); expect(axios.get.mock.calls.length).toEqual(1); }); }); });