mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	Merge pull request #1408 from Unleash/feat/init-client-tokens
Load Client Tokens From Environment on Startup
This commit is contained in:
		
						commit
						3910e23d2d
					
				@ -18,7 +18,7 @@ test('should create default config', async () => {
 | 
				
			|||||||
    expect(config).toMatchSnapshot();
 | 
					    expect(config).toMatchSnapshot();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('should add initApiToken from options', async () => {
 | 
					test('should add initApiToken for admin token from options', async () => {
 | 
				
			||||||
    const token = {
 | 
					    const token = {
 | 
				
			||||||
        environment: '*',
 | 
					        environment: '*',
 | 
				
			||||||
        project: '*',
 | 
					        project: '*',
 | 
				
			||||||
@ -52,7 +52,41 @@ test('should add initApiToken from options', async () => {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('should add initApiToken from env var', async () => {
 | 
					test('should add initApiToken for client token from options', async () => {
 | 
				
			||||||
 | 
					    const token = {
 | 
				
			||||||
 | 
					        environment: 'development',
 | 
				
			||||||
 | 
					        project: 'default',
 | 
				
			||||||
 | 
					        secret: 'default:development.some-random-string',
 | 
				
			||||||
 | 
					        type: ApiTokenType.CLIENT,
 | 
				
			||||||
 | 
					        username: 'admin',
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const config = createConfig({
 | 
				
			||||||
 | 
					        db: {
 | 
				
			||||||
 | 
					            host: 'localhost',
 | 
				
			||||||
 | 
					            port: 4242,
 | 
				
			||||||
 | 
					            user: 'unleash',
 | 
				
			||||||
 | 
					            password: 'password',
 | 
				
			||||||
 | 
					            database: 'unleash_db',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        server: {
 | 
				
			||||||
 | 
					            port: 4242,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        authentication: {
 | 
				
			||||||
 | 
					            initApiTokens: [token],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(config.authentication.initApiTokens).toHaveLength(1);
 | 
				
			||||||
 | 
					    expect(config.authentication.initApiTokens[0].environment).toBe(
 | 
				
			||||||
 | 
					        token.environment,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(config.authentication.initApiTokens[0].project).toBe(token.project);
 | 
				
			||||||
 | 
					    expect(config.authentication.initApiTokens[0].type).toBe(
 | 
				
			||||||
 | 
					        ApiTokenType.CLIENT,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('should add initApiToken for admin token from env var', async () => {
 | 
				
			||||||
    process.env.INIT_ADMIN_API_TOKENS = '*:*.some-token1, *:*.some-token2';
 | 
					    process.env.INIT_ADMIN_API_TOKENS = '*:*.some-token1, *:*.some-token2';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const config = createConfig({
 | 
					    const config = createConfig({
 | 
				
			||||||
@ -81,7 +115,7 @@ test('should add initApiToken from env var', async () => {
 | 
				
			|||||||
    delete process.env.INIT_ADMIN_API_TOKENS;
 | 
					    delete process.env.INIT_ADMIN_API_TOKENS;
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('should validate initApiToken from env var', async () => {
 | 
					test('should validate initApiToken for admin token from env var', async () => {
 | 
				
			||||||
    process.env.INIT_ADMIN_API_TOKENS = 'invalidProject:*:some-token1';
 | 
					    process.env.INIT_ADMIN_API_TOKENS = 'invalidProject:*:some-token1';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    expect(() => createConfig({})).toThrow(
 | 
					    expect(() => createConfig({})).toThrow(
 | 
				
			||||||
@ -91,8 +125,19 @@ test('should validate initApiToken from env var', async () => {
 | 
				
			|||||||
    delete process.env.INIT_ADMIN_API_TOKENS;
 | 
					    delete process.env.INIT_ADMIN_API_TOKENS;
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('should validate initApiToken for client token from env var', async () => {
 | 
				
			||||||
 | 
					    process.env.INIT_CLIENT_API_TOKENS = '*:*:some-token1';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(() => createConfig({})).toThrow(
 | 
				
			||||||
 | 
					        'Client token cannot be scoped to all environments',
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    delete process.env.INIT_CLIENT_API_TOKENS;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('should merge initApiToken from options and env vars', async () => {
 | 
					test('should merge initApiToken from options and env vars', async () => {
 | 
				
			||||||
    process.env.INIT_ADMIN_API_TOKENS = '*:*.some-token1, *:*.some-token2';
 | 
					    process.env.INIT_ADMIN_API_TOKENS = '*:*.some-token1, *:*.some-token2';
 | 
				
			||||||
 | 
					    process.env.INIT_CLIENT_API_TOKENS = 'default:development.some-token1';
 | 
				
			||||||
    const token = {
 | 
					    const token = {
 | 
				
			||||||
        environment: '*',
 | 
					        environment: '*',
 | 
				
			||||||
        project: '*',
 | 
					        project: '*',
 | 
				
			||||||
@ -116,6 +161,66 @@ test('should merge initApiToken from options and env vars', async () => {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    expect(config.authentication.initApiTokens).toHaveLength(3);
 | 
					    expect(config.authentication.initApiTokens).toHaveLength(4);
 | 
				
			||||||
 | 
					    delete process.env.INIT_CLIENT_API_TOKENS;
 | 
				
			||||||
    delete process.env.INIT_ADMIN_API_TOKENS;
 | 
					    delete process.env.INIT_ADMIN_API_TOKENS;
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('should add initApiToken for client token from env var', async () => {
 | 
				
			||||||
 | 
					    process.env.INIT_CLIENT_API_TOKENS =
 | 
				
			||||||
 | 
					        'default:development.some-token1, default:development.some-token2';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const config = createConfig({
 | 
				
			||||||
 | 
					        db: {
 | 
				
			||||||
 | 
					            host: 'localhost',
 | 
				
			||||||
 | 
					            port: 4242,
 | 
				
			||||||
 | 
					            user: 'unleash',
 | 
				
			||||||
 | 
					            password: 'password',
 | 
				
			||||||
 | 
					            database: 'unleash_db',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        server: {
 | 
				
			||||||
 | 
					            port: 4242,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(config.authentication.initApiTokens).toHaveLength(2);
 | 
				
			||||||
 | 
					    expect(config.authentication.initApiTokens[0].environment).toBe(
 | 
				
			||||||
 | 
					        'development',
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(config.authentication.initApiTokens[0].project).toBe('default');
 | 
				
			||||||
 | 
					    expect(config.authentication.initApiTokens[0].type).toBe(
 | 
				
			||||||
 | 
					        ApiTokenType.CLIENT,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(config.authentication.initApiTokens[0].secret).toBe(
 | 
				
			||||||
 | 
					        'default:development.some-token1',
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    delete process.env.INIT_CLIENT_API_TOKENS;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('should handle cases where no env var specified for tokens', async () => {
 | 
				
			||||||
 | 
					    const token = {
 | 
				
			||||||
 | 
					        environment: '*',
 | 
				
			||||||
 | 
					        project: '*',
 | 
				
			||||||
 | 
					        secret: '*:*.some-random-string',
 | 
				
			||||||
 | 
					        type: ApiTokenType.ADMIN,
 | 
				
			||||||
 | 
					        username: 'admin',
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const config = createConfig({
 | 
				
			||||||
 | 
					        db: {
 | 
				
			||||||
 | 
					            host: 'localhost',
 | 
				
			||||||
 | 
					            port: 4242,
 | 
				
			||||||
 | 
					            user: 'unleash',
 | 
				
			||||||
 | 
					            password: 'password',
 | 
				
			||||||
 | 
					            database: 'unleash_db',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        server: {
 | 
				
			||||||
 | 
					            port: 4242,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        authentication: {
 | 
				
			||||||
 | 
					            initApiTokens: [token],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(config.authentication.initApiTokens).toHaveLength(1);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -182,27 +182,39 @@ const formatServerOptions = (
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const loadInitApiTokens = () => {
 | 
					const loadTokensFromString = (tokenString: String, tokenType: ApiTokenType) => {
 | 
				
			||||||
    if (process.env.INIT_ADMIN_API_TOKENS) {
 | 
					    if (!tokenString) {
 | 
				
			||||||
        const initApiTokens = process.env.INIT_ADMIN_API_TOKENS.split(/,\s?/);
 | 
					 | 
				
			||||||
        const tokens = initApiTokens.map((secret) => {
 | 
					 | 
				
			||||||
            const [project = '*', rest] = secret.split(':');
 | 
					 | 
				
			||||||
            const [environment = '*'] = rest.split('.');
 | 
					 | 
				
			||||||
            const token = {
 | 
					 | 
				
			||||||
                createdAt: undefined,
 | 
					 | 
				
			||||||
                project,
 | 
					 | 
				
			||||||
                environment,
 | 
					 | 
				
			||||||
                secret,
 | 
					 | 
				
			||||||
                type: ApiTokenType.ADMIN,
 | 
					 | 
				
			||||||
                username: 'admin',
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
            validateApiToken(token);
 | 
					 | 
				
			||||||
            return token;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        return tokens;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        return [];
 | 
					        return [];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    const initApiTokens = tokenString.split(/,\s?/);
 | 
				
			||||||
 | 
					    const tokens = initApiTokens.map((secret) => {
 | 
				
			||||||
 | 
					        const [project = '*', rest] = secret.split(':');
 | 
				
			||||||
 | 
					        const [environment = '*'] = rest.split('.');
 | 
				
			||||||
 | 
					        const token = {
 | 
				
			||||||
 | 
					            createdAt: undefined,
 | 
				
			||||||
 | 
					            project,
 | 
				
			||||||
 | 
					            environment,
 | 
				
			||||||
 | 
					            secret,
 | 
				
			||||||
 | 
					            type: tokenType,
 | 
				
			||||||
 | 
					            username: 'admin',
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        validateApiToken(token);
 | 
				
			||||||
 | 
					        return token;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return tokens;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const loadInitApiTokens = () => {
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					        ...loadTokensFromString(
 | 
				
			||||||
 | 
					            process.env.INIT_ADMIN_API_TOKENS,
 | 
				
			||||||
 | 
					            ApiTokenType.ADMIN,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        ...loadTokensFromString(
 | 
				
			||||||
 | 
					            process.env.INIT_CLIENT_API_TOKENS,
 | 
				
			||||||
 | 
					            ApiTokenType.CLIENT,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function createConfig(options: IUnleashOptions): IUnleashConfig {
 | 
					export function createConfig(options: IUnleashOptions): IUnleashConfig {
 | 
				
			||||||
 | 
				
			|||||||
@ -89,7 +89,7 @@ unleash.start(unleashOptions);
 | 
				
			|||||||
     ```
 | 
					     ```
 | 
				
			||||||
      The tokens can be of any API token type. Note that _admin_ tokens **must** target all environments and projects (i.e. use `'*'` for `environments` and `project` and start the secret with `*:*.`).
 | 
					      The tokens can be of any API token type. Note that _admin_ tokens **must** target all environments and projects (i.e. use `'*'` for `environments` and `project` and start the secret with `*:*.`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      You can also use the environment variable `INIT_ADMIN_API_TOKENS` to create API tokens on startup. This variable should be set to a comma-separated list of API tokens to initialize (for instance `*:*.some-random-string, *:*.some-other-token`). With the environment variable, all tokens will be created as admin tokens and Unleash will assign a username automatically.
 | 
					      You can also use the environment variables `INIT_ADMIN_API_TOKENS` or `INIT_CLIENT_API_TOKENS` to create API admin or client tokens on startup. Both variables require a comma-separated list of API tokens to initialize (for instance `*:*.some-random-string, *:*.some-other-token`). The tokens found in `INIT_ADMIN_API_TOKENS` and `INIT_CLIENT_API_TOKENS` will be created as admin and client tokens respectively and Unleash will assign a username automatically.
 | 
				
			||||||
- **databaseUrl** - (_deprecated_) the postgres database url to connect to. Only used if _db_ object is not specified, and overrides the _db_ object and any environment variables that change parts of it (like `DATABASE_SSL`). Should include username/password. This value may also be set via the `DATABASE_URL` environment variable. Alternatively, if you would like to read the database url from a file, you may set the `DATABASE_URL_FILE` environment variable with the full file path. The contents of the file must be the database url exactly.
 | 
					- **databaseUrl** - (_deprecated_) the postgres database url to connect to. Only used if _db_ object is not specified, and overrides the _db_ object and any environment variables that change parts of it (like `DATABASE_SSL`). Should include username/password. This value may also be set via the `DATABASE_URL` environment variable. Alternatively, if you would like to read the database url from a file, you may set the `DATABASE_URL_FILE` environment variable with the full file path. The contents of the file must be the database url exactly.
 | 
				
			||||||
- **db** - The database configuration object taking the following properties:
 | 
					- **db** - The database configuration object taking the following properties:
 | 
				
			||||||
  - _user_ - the database username (`DATABASE_USERNAME`)
 | 
					  - _user_ - the database username (`DATABASE_USERNAME`)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user