diff --git a/packages/core/src/__mocks__/index.ts b/packages/core/src/__mocks__/index.ts index 47eb23adf..9c3c5ff6f 100644 --- a/packages/core/src/__mocks__/index.ts +++ b/packages/core/src/__mocks__/index.ts @@ -14,6 +14,7 @@ export * from './user'; export const mockApplication: Application = { id: 'foo', + secret: 'randomId', name: 'foo', type: ApplicationType.SPA, description: null, diff --git a/packages/core/src/database/seed.ts b/packages/core/src/database/seed.ts index c0bc3ab05..1ab9bca58 100644 --- a/packages/core/src/database/seed.ts +++ b/packages/core/src/database/seed.ts @@ -8,6 +8,8 @@ import { createPool, parseDsn, sql, stringifyDsn } from 'slonik'; import { createInterceptors } from 'slonik-interceptor-preset'; import { raw } from 'slonik-sql-tag-raw'; +import { buildApplicationSecret } from '@/utils/id'; + import { convertToPrimitiveOrSql } from './utils'; const { @@ -84,7 +86,7 @@ export const createDatabaseCli = (dsn: string) => { pool.query(insertInto(managementResource, 'resources')), pool.query(insertInto(createDefaultSetting(), 'settings')), pool.query(insertInto(defaultSignInExperience, 'sign_in_experiences')), - pool.query(insertInto(createDemoAppApplication(), 'applications')), + pool.query(insertInto(createDemoAppApplication(buildApplicationSecret()), 'applications')), pool.query(insertInto(defaultRole, 'roles')), ]); console.log(`${chalk.blue('[seed-tables]')} Seed tables succeeded.`); diff --git a/packages/core/src/oidc/adapter.test.ts b/packages/core/src/oidc/adapter.test.ts index 46cd4d905..36dc24130 100644 --- a/packages/core/src/oidc/adapter.test.ts +++ b/packages/core/src/oidc/adapter.test.ts @@ -27,6 +27,11 @@ jest.mock('@/queries/oidc-model-instance', () => ({ revokeInstanceByGrantId: jest.fn(), })); +jest.mock('@/utils/id', () => ({ + // eslint-disable-next-line unicorn/consistent-function-scoping + buildIdGenerator: jest.fn(() => () => 'randomId'), +})); + const now = Date.now(); jest.mock( @@ -54,6 +59,7 @@ describe('postgres Adapter', () => { const { id: client_id, name: client_name, + secret: client_secret, type, oidcClientMetadata, customClientMetadata, @@ -62,6 +68,7 @@ describe('postgres Adapter', () => { expect(application).toEqual({ client_id, client_name, + client_secret, application_type: getApplicationTypeString(type), grant_types: ['authorization_code', 'refresh_token'], token_endpoint_auth_method: 'none', diff --git a/packages/core/src/oidc/adapter.ts b/packages/core/src/oidc/adapter.ts index 3a2de6dc9..c65124665 100644 --- a/packages/core/src/oidc/adapter.ts +++ b/packages/core/src/oidc/adapter.ts @@ -57,16 +57,19 @@ export default function postgresAdapter(modelName: string): ReturnType Promise.reject(new Error('Not implemented')); const transpileClient = ({ id: client_id, + secret: client_secret, name: client_name, type, oidcClientMetadata, customClientMetadata, }: CreateApplication): AllClientMetadata => ({ client_id, + client_secret, client_name, application_type: getApplicationTypeString(type), grant_types: Object.values(GrantType), - token_endpoint_auth_method: 'none', + token_endpoint_auth_method: + type === ApplicationType.Traditional ? 'client_secret_basic' : 'none', ...snakecaseKeys(oidcClientMetadata), ...(client_id === demoAppApplicationId && snakecaseKeys(buildDemoAppUris(oidcClientMetadata))), diff --git a/packages/core/src/routes/application.test.ts b/packages/core/src/routes/application.test.ts index 9508beb00..c74ac6bd1 100644 --- a/packages/core/src/routes/application.test.ts +++ b/packages/core/src/routes/application.test.ts @@ -32,6 +32,7 @@ jest.mock('@/queries/application', () => ({ jest.mock('@/utils/id', () => ({ // eslint-disable-next-line unicorn/consistent-function-scoping buildIdGenerator: jest.fn(() => () => 'randomId'), + buildApplicationSecret: jest.fn(() => 'randomId'), })); const customClientMetadata = { @@ -62,6 +63,7 @@ describe('application route', () => { expect(response.body).toEqual({ ...mockApplication, id: 'randomId', + secret: 'randomId', name, description, type, diff --git a/packages/core/src/routes/application.ts b/packages/core/src/routes/application.ts index 762d9a13d..62f9e18ce 100644 --- a/packages/core/src/routes/application.ts +++ b/packages/core/src/routes/application.ts @@ -12,7 +12,7 @@ import { updateApplicationById, findTotalNumberOfApplications, } from '@/queries/application'; -import { buildIdGenerator } from '@/utils/id'; +import { buildApplicationSecret, buildIdGenerator } from '@/utils/id'; import { AuthedRouter } from './types'; @@ -47,6 +47,7 @@ export default function applicationRoutes(router: T) { ctx.body = await insertApplication({ id: applicationId(), + secret: buildApplicationSecret(), oidcClientMetadata: buildOidcClientMetadata(oidcClientMetadata), ...rest, }); diff --git a/packages/core/src/utils/id.ts b/packages/core/src/utils/id.ts index 5072c37ee..c57dced5e 100644 --- a/packages/core/src/utils/id.ts +++ b/packages/core/src/utils/id.ts @@ -3,3 +3,5 @@ import { customAlphabet } from 'nanoid'; export const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; export const buildIdGenerator = (size: number) => customAlphabet(alphabet, size); + +export const buildApplicationSecret = buildIdGenerator(64); diff --git a/packages/schemas/src/seeds/application.ts b/packages/schemas/src/seeds/application.ts index 28375affc..1caac5576 100644 --- a/packages/schemas/src/seeds/application.ts +++ b/packages/schemas/src/seeds/application.ts @@ -9,8 +9,9 @@ export const adminConsoleApplicationId = 'admin-console'; export const demoAppApplicationId = 'demo-app'; -export const createDemoAppApplication = (): Readonly => ({ +export const createDemoAppApplication = (secret: string): Readonly => ({ id: demoAppApplicationId, + secret, name: 'Demo App', description: 'Logto demo app.', type: ApplicationType.SPA, diff --git a/packages/schemas/tables/applications.sql b/packages/schemas/tables/applications.sql index e03613aa7..5de67a33f 100644 --- a/packages/schemas/tables/applications.sql +++ b/packages/schemas/tables/applications.sql @@ -3,6 +3,7 @@ create type application_type as enum ('Native', 'SPA', 'Traditional'); create table applications ( id varchar(21) not null, name varchar(256) not null, + secret varchar(64) not null, description text, type application_type not null, oidc_client_metadata jsonb /* @use OidcClientMetadata */ not null,