Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
ignore-workspace-root-check=true
131 changes: 99 additions & 32 deletions __test__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { randomUUID } from 'node:crypto';
import { GenericContainer, StartedTestContainer, Wait } from 'testcontainers';
import { ApiResponse, AuthToken, Authorizer } from '../lib';

const authorizerConfig = {
const authorizerConfig: {
authorizerURL: string;
redirectURL: string;
adminSecret: string;
clientID?: string;
} = {
authorizerURL: 'http://localhost:8080',
redirectURL: 'http://localhost:8080/app',
// clientID: '3fab5e58-5693-46f2-8123-83db8133cd22',
adminSecret: 'secret',
};

Expand All @@ -18,22 +23,54 @@ const testConfig = {
maginLinkLoginEmail: 'test_magic_link@test.com',
};

// Using etheral.email for email sink: https://ethereal.email/create
const authorizerENV = {
ENV: 'production',
DATABASE_URL: 'data.db',
DATABASE_TYPE: 'sqlite',
CUSTOM_ACCESS_TOKEN_SCRIPT:
'function(user,tokenPayload){var data = tokenPayload;data.extra = {\'x-extra-id\': user.id};return data;}',
DISABLE_PLAYGROUND: 'true',
SMTP_HOST: 'smtp.ethereal.email',
SMTP_PASSWORD: 'WncNxwVFqb6nBjKDQJ',
SMTP_USERNAME: 'sydnee.lesch77@ethereal.email',
LOG_LELVEL: 'debug',
SMTP_PORT: '587',
SENDER_EMAIL: 'test@authorizer.dev',
ADMIN_SECRET: 'secret',
};
// Build v2 CLI args for authorizer (see authorizer/cmd/root.go). Using etheral.email for email sink.
function buildAuthorizerCliArgs(): { args: string[]; clientId: string } {
const clientId = randomUUID();
const clientSecret = randomUUID();
const jwtSecret = randomUUID();
const customAccessTokenScript =
'function(user,tokenPayload){var data = tokenPayload;data.extra = {\'x-extra-id\': user.id};return data;}';

const args = [
'--client-id',
clientId,
'--client-secret',
clientSecret,
'--jwt-type',
'HS256',
'--jwt-secret',
jwtSecret,
'--admin-secret',
authorizerConfig.adminSecret,
'--env',
'production',
'--database-type',
'sqlite',
'--database-url',
'/tmp/authorizer.db',
'--custom-access-token-script',
customAccessTokenScript,
'--enable-playground',
'false',
'--log-level',
'debug',
'--smtp-host',
'smtp.ethereal.email',
'--smtp-port',
'587',
'--smtp-username',
'sydnee.lesch77@ethereal.email',
'--smtp-password',
'WncNxwVFqb6nBjKDQJ',
'--smtp-sender-email',
'test@authorizer.dev',
'--enable-email-verification',
'true',
'--enable-magic-link-login',
'true',
];
return { args, clientId };
}

// const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

Expand All @@ -46,8 +83,10 @@ describe('Integration Tests - authorizer-js', () => {
let authorizer: Authorizer;

beforeAll(async () => {
container = await new GenericContainer('lakhansamani/authorizer:latest')
.withEnvironment(authorizerENV)
const { args, clientId } = buildAuthorizerCliArgs();

container = await new GenericContainer('lakhansamani/authorizer:2.0.0-rc.6')
.withCommand(args)
.withExposedPorts(8080)
.withWaitStrategy(Wait.forHttp('/health', 8080).forStatusCode(200))
.start();
Expand All @@ -58,15 +97,12 @@ describe('Integration Tests - authorizer-js', () => {
authorizerConfig.redirectURL = `http://${container.getHost()}:${container.getMappedPort(
8080,
)}/app`;
authorizerConfig.clientID = clientId;
console.log('Authorizer URL:', authorizerConfig.authorizerURL);
authorizer = new Authorizer(authorizerConfig);
// get metadata
const metadataRes = await authorizer.getMetaData();
// await sleep(50000);
expect(metadataRes?.data).toBeDefined();
if (metadataRes?.data?.client_id) {
authorizer.config.clientID = metadataRes?.data?.client_id;
}
expect(metadataRes?.data?.client_id).toBe(clientId);
});

afterAll(async () => {
Expand Down Expand Up @@ -101,10 +137,13 @@ describe('Integration Tests - authorizer-js', () => {
(i: { email: string }) => i.email === testConfig.email,
);
expect(item).not.toBeNull();
expect(item?.token).toBeDefined();

const verifyEmailRes = await authorizer.verifyEmail({ token: item.token });
expect(verifyEmailRes?.data).toBeDefined();
expect(verifyEmailRes?.errors).toHaveLength(0);
expect(verifyEmailRes?.data?.access_token).toBeDefined();
expect(verifyEmailRes?.data?.access_token).not.toBeNull();
expect(verifyEmailRes?.data?.access_token?.length).toBeGreaterThan(0);
});

Expand All @@ -117,13 +156,23 @@ describe('Integration Tests - authorizer-js', () => {
});
expect(loginRes?.data).toBeDefined();
expect(loginRes?.errors).toHaveLength(0);
expect(loginRes?.data?.access_token.length).not.toEqual(0);
expect(loginRes?.data?.refresh_token?.length).not.toEqual(0);
expect(loginRes?.data?.expires_in).not.toEqual(0);
expect(loginRes?.data?.id_token.length).not.toEqual(0);
expect(loginRes?.data?.access_token).toBeDefined();
expect(loginRes?.data?.access_token).not.toBeNull();
expect(loginRes?.data?.access_token?.length).toBeGreaterThan(0);
expect(loginRes?.data?.refresh_token).toBeDefined();
expect(loginRes?.data?.refresh_token).not.toBeNull();
expect(loginRes?.data?.refresh_token?.length).toBeGreaterThan(0);
expect(loginRes?.data?.expires_in).toBeDefined();
expect(loginRes?.data?.expires_in).not.toBeNull();
expect(loginRes?.data?.expires_in).toBeGreaterThan(0);
expect(loginRes?.data?.id_token).toBeDefined();
expect(loginRes?.data?.id_token).not.toBeNull();
expect(loginRes?.data?.id_token?.length).toBeGreaterThan(0);
});

it('should validate jwt token', async () => {
expect(loginRes?.data?.access_token).toBeDefined();
expect(loginRes?.data?.access_token).not.toBeNull();
const validateRes = await authorizer.validateJWTToken({
token_type: 'access_token',
token: loginRes?.data?.access_token || '',
Expand All @@ -134,6 +183,8 @@ describe('Integration Tests - authorizer-js', () => {
});

it('should update profile successfully', async () => {
expect(loginRes?.data?.access_token).toBeDefined();
expect(loginRes?.data?.access_token).not.toBeNull();
const updateProfileRes = await authorizer.updateProfile(
{
given_name: 'bob',
Expand All @@ -147,28 +198,36 @@ describe('Integration Tests - authorizer-js', () => {
});

it('should fetch profile successfully', async () => {
expect(loginRes?.data?.access_token).toBeDefined();
expect(loginRes?.data?.access_token).not.toBeNull();
const profileRes = await authorizer.getProfile({
Authorization: `Bearer ${loginRes?.data?.access_token}`,
});
expect(profileRes?.data).toBeDefined();
expect(profileRes?.errors).toHaveLength(0);
expect(profileRes?.data?.given_name).toBeDefined();
expect(profileRes?.data?.given_name).toMatch('bob');
});

it('should get access_token using refresh_token', async () => {
expect(loginRes?.data?.refresh_token).toBeDefined();
expect(loginRes?.data?.refresh_token).not.toBeNull();
const tokenRes = await authorizer.getToken({
grant_type: 'refresh_token',
refresh_token: loginRes?.data?.refresh_token,
refresh_token: loginRes?.data?.refresh_token || '',
});
expect(tokenRes?.data).toBeDefined();
expect(tokenRes?.errors).toHaveLength(0);
expect(tokenRes?.data?.access_token.length).not.toEqual(0);
expect(tokenRes?.data?.access_token).toBeDefined();
expect(tokenRes?.data?.access_token?.length).toBeGreaterThan(0);
if (loginRes && loginRes.data) {
loginRes.data.access_token = tokenRes?.data?.access_token || '';
}
});

it('should deactivate account', async () => {
expect(loginRes?.data?.access_token).toBeDefined();
expect(loginRes?.data?.access_token).not.toBeNull();
const deactivateRes = await authorizer.deactivateAccount({
Authorization: `Bearer ${loginRes?.data?.access_token}`,
});
Expand All @@ -177,11 +236,13 @@ describe('Integration Tests - authorizer-js', () => {
});

it('should throw error while accessing profile after deactivation', async () => {
expect(loginRes?.data?.access_token).toBeDefined();
const resp = await authorizer.getProfile({
Authorization: `Bearer ${loginRes?.data?.access_token}`,
});
expect(resp?.data).toBeUndefined();
expect(resp?.errors).toHaveLength(1);
expect(resp?.errors).toBeDefined();
expect(resp?.errors.length).toBeGreaterThan(0);
});

describe('magic link login', () => {
Expand All @@ -195,22 +256,28 @@ describe('Integration Tests - authorizer-js', () => {
it('should verify email', async () => {
const verificationRequestsRes = await authorizer.graphqlQuery({
query: verificationRequests,
variables: {},
headers: {
'x-authorizer-admin-secret': authorizerConfig.adminSecret,
},
});
const requests =
verificationRequestsRes?.data?._verification_requests
.verification_requests;
expect(verificationRequestsRes?.data).toBeDefined();
expect(verificationRequestsRes?.errors).toHaveLength(0);
const item = requests.find(
(i: { email: string }) => i.email === testConfig.maginLinkLoginEmail,
);
expect(item).not.toBeNull();
expect(item?.token).toBeDefined();
const verifyEmailRes = await authorizer.verifyEmail({
token: item.token,
});
expect(verifyEmailRes?.data).toBeDefined();
expect(verifyEmailRes?.errors).toHaveLength(0);
expect(verifyEmailRes?.data?.user).toBeDefined();
expect(verifyEmailRes?.data?.user?.signup_methods).toBeDefined();
expect(verifyEmailRes?.data?.user?.signup_methods).toContain(
'magic_link_login',
);
Expand Down
12 changes: 3 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@authorizerdev/authorizer-js",
"version": "2.0.3",
"version": "3.0.0-rc.1",
"packageManager": "pnpm@7.28.0",
"author": "Lakhan Samani",
"license": "MIT",
Expand Down Expand Up @@ -30,14 +30,14 @@
"node": ">=16"
},
"scripts": {
"start": "rollup -w --config rollup.test.config.js",
"ts-types": "tsc --emitDeclarationOnly --outDir lib",
"start": "tsup --watch",
"build": "tsup",
"test": "npm run build && jest --testTimeout=500000 --runInBand",
"prepare": "husky install",
"prepublishOnly": "npm run build",
"release": "pnpm build && bumpp --commit --push --tag && pnpm publish",
"release-beta": "pnpm build && bumpp --commit --push --tag && pnpm publish --tag beta",
"release-rc": "pnpm build && pnpm publish --tag rc",
"lint": "eslint --ignore-pattern 'tsup.config.ts' --ext .ts,.tsx,.js,.jsx,.json .",
"lint:fix": "eslint --ignore-pattern 'tsup.config.ts' --ext .ts,.tsx,.js,.jsx,.json . --fix"
},
Expand All @@ -54,9 +54,6 @@
},
"devDependencies": {
"@antfu/eslint-config": "^2.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^11.1.5",
"@swc/core": "^1.3.99",
"@types/jest": "^29.5.12",
"@types/node": "^20.9.4",
Expand All @@ -67,9 +64,6 @@
"husky": "^8.0.0",
"jest": "^29.7.0",
"lint-staged": "^15.2.0",
"rollup": "^2.79.1",
"rollup-plugin-filesize": "^10.0.0",
"rollup-plugin-serve": "^2.0.2",
"testcontainers": "^10.3.2",
"ts-jest": "^29.1.1",
"tslib": "^2.6.2",
Expand Down
Loading
Loading