Skip to content

Commit

Permalink
api: configurable refresh and access tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
SamuelPull committed Nov 21, 2024
1 parent ea21621 commit 4800754
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 10 deletions.
6 changes: 4 additions & 2 deletions api/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
| **ORGANIZATION** | no | MyOrga | In the blockchain network, each node is represented by its organization name. This environment variable sets this organization name. It is used to create the organization stream on the blockchain and is also displayed in the frontend's top right corner. Minimal value: 1. Maximal value: 100. |
| **PORT** | no | 8091 | The port used to expose the API for your installation. Example: If you run TruBudget locally and set API_PORT to `8080`, you can reach the API via `localhost:8080/api`. Value is a port with minimal value 0 and maximal value 65535 |
| **ORGANIZATION_VAULT_SECRET** | yes | - | This is the key to en-/decrypt user data of an organization. If you want to add a new node for your organization, you want users to be able to log in on either node. **Caution:** If you want to run TruBudget in production, make sure NOT to use the default value from the `.env.example` file! Minimal value: 5. |
| **ROOT_SECRET** | no | 8d0ab15d21b6d2c48d834bad4785a52126573906c84e6120506fce35f5ce4708 | The root secret is the password for the root user. If you start with an empty blockchain, the root user is needed to add other users, approve new nodes,.. If you don't set a value via the environment variable, the API generates one randomly and prints it to the console **Caution:** If you want to run TruBudget in production, make sure to set a secure root secret. Minimal value: 8. |
| **ROOT_SECRET** | no | 95d002575da0517b7822253314971fc51b8ffe8df9829086321807e6d90dd1a4 | The root secret is the password for the root user. If you start with an empty blockchain, the root user is needed to add other users, approve new nodes,.. If you don't set a value via the environment variable, the API generates one randomly and prints it to the console **Caution:** If you want to run TruBudget in production, make sure to set a secure root secret. Minimal value: 8. |
| **MULTICHAIN_RPC_HOST** | no | localhost | The IP address of the blockchain (not multichain daemon,but they are usally the same) you want to connect to. |
| **MULTICHAIN_RPC_PORT** | no | 8000 | The Port of the blockchain where the server is available for incoming http connections (e.g. readiness, versions, backup and restore) |
| **MULTICHAIN_PROTOCOL** | no | http | The protocol used to expose the multichain daemon of your Trubudget blockchain installation(bc). The protocol used to connect to the multichain daemon(api). This will be used internally for the communication between the API and the multichain daemon. |
Expand All @@ -18,7 +18,7 @@
| **BLOCKCHAIN_PROTOCOL** | no | http | The Protocol of the blockchain where the server is available for incoming http connections. |
| **SWAGGER_BASEPATH** `deprecated` | no | - | deprecated This variable was used to choose which environment (prod or test) is used for testing the requests. The variable is deprecated now, as the Swagger documentation can be used for the prod and test environment separately. Example values: "/". |
| **JWT_ALGORITHM** | no | HS256 | Algorithm used for signing and verifying JWTs. |
| **JWT_SECRET** | yes (if JWT_ALGORITHM=RS256) | 9640f5d6c8af1bc72275 | A string that is used to sign JWT which are created by the authenticate endpoint of the api. If JWT_ALGORITHM is set to `RS256`, this is required and holds BASE64 encoded PEM encoded private key for RSA. |
| **JWT_SECRET** | yes (if JWT_ALGORITHM=RS256) | d842248e4fd8cc95267d | A string that is used to sign JWT which are created by the authenticate endpoint of the api. If JWT_ALGORITHM is set to `RS256`, this is required and holds BASE64 encoded PEM encoded private key for RSA. |
| **JWT_PUBLIC_KEY** | yes (if JWT_ALGORITHM=RS256) | - | If JWT_ALGORITHM is set to `RS256`, this is required and holds BASE64 encoded PEM encoded public key for RSA. |
| **DOCUMENT_FEATURE_ENABLED** | no | - | If true, all uploaded documents are stored using trubudget's storage-service. If false, the document feature of TruBudget is disabled, and trying to upload a document will result in an error. |
| **DOCUMENT_EXTERNAL_LINKS_ENABLED** | no | - | If true, it is possible to use external documents links also without TruBudget's storage-service. If false, the external documents links feature of TruBudget is still possible to use in case DOCUMENT_FEATURE_ENABLED equals "true". |
Expand All @@ -38,6 +38,8 @@
| **AUTHPROXY_JWS_SIGNATURE** | yes (if AUTHPROXY_ENABLED=true) | - | secret/public key/certificate for verifying auth proxy token signature |
| **DB_TYPE** | no | pg | - |
| **SQL_DEBUG** | no | - | - |
| **REFRESH_TOKEN_EXPIRATION** | no | 8 | Refresh token expiration in hours |
| **ACCESS_TOKEN_EXPIRATION** | no | 15 | Access token expiration in minutes |
| **REFRESH_TOKEN_STORAGE** | no | - | Determining the type of storage for refresh tokens. Allowed values are "db" or "memory" or blank to disable refresh token functionality. |
| **API_DB_USER** | yes (if REFRESH_TOKEN_STORAGE=db) | postgres | Database user for database connection, e.g. postgres |
| **API_DB_PASSWORD** | yes (if REFRESH_TOKEN_STORAGE=db) | test | Database password for database connection |
Expand Down
8 changes: 4 additions & 4 deletions api/src/authenticationUtils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as jsonwebtoken from "jsonwebtoken";

import { JwtConfig } from "./config";
import { config, JwtConfig } from "./config";

export const refreshTokenExpirationInDays = 8;
export const accessTokenExpirationInMinutesWithrefreshToken = 10;
export const refreshTokenExpirationInHours = config.refreshTokenExpiration;
export const accessTokenExpirationInMinutesWithrefreshToken = config.accessTokenExpiration;

/**
* Creates a refresh JWT Token
Expand All @@ -18,7 +18,7 @@ export function createRefreshJWTToken(
): string {
const secretOrPrivateKey = algorithm === "RS256" ? Buffer.from(key, "base64") : key;
return jsonwebtoken.sign(payload, secretOrPrivateKey, {
expiresIn: `${refreshTokenExpirationInDays}d`,
expiresIn: `${refreshTokenExpirationInHours}h`,
algorithm,
});
}
6 changes: 6 additions & 0 deletions api/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ interface ProcessEnvVars {
API_DB_PORT: string;
API_DB_SSL: string;
API_DB_SCHEMA: string;
REFRESH_TOKEN_EXPIRATION: string;
ACCESS_TOKEN_EXPIRATION: string;
API_REFRESH_TOKENS_TABLE: string;
REFRESH_TOKEN_STORAGE?: string; // "db" || "memory" || undefined
}
Expand Down Expand Up @@ -122,6 +124,8 @@ interface Config {
db: DatabaseConfig;
dbType: string;
sqlDebug: boolean | undefined;
accessTokenExpiration: number;
refreshTokenExpiration: number;
refreshTokensTable: string | undefined;
refreshTokenStorage: string | undefined;
snapshotEventInterval: number;
Expand Down Expand Up @@ -198,6 +202,8 @@ export const config: Config = {
},
dbType: envVars.DB_TYPE,
sqlDebug: envVars.SQL_DEBUG,
accessTokenExpiration: envVars.ACCESS_TOKEN_EXPIRATION,
refreshTokenExpiration: envVars.REFRESH_TOKEN_EXPIRATION,
refreshTokensTable: envVars.API_REFRESH_TOKENS_TABLE,
refreshTokenStorage: envVars.REFRESH_TOKEN_STORAGE,
snapshotEventInterval: envVars.SNAPSHOT_EVENT_INTERVAL,
Expand Down
10 changes: 10 additions & 0 deletions api/src/envVarsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,16 @@ export const envVarsSchema = Joi.object({
.empty(["", null])
.default("public")
.note('Database schema, e.g. "public".'),
REFRESH_TOKEN_EXPIRATION: Joi.number()
.default(8)
.allow("")
.empty(["", null])
.note("Refresh token expiration in hours"),
ACCESS_TOKEN_EXPIRATION: Joi.number()
.default(15)
.allow("")
.empty(["", null])
.note("Access token expiration in minutes"),
API_REFRESH_TOKENS_TABLE: Joi.string()
.empty(["", null])
.default("refresh_token")
Expand Down
4 changes: 2 additions & 2 deletions api/src/user_authenticate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { VError } from "verror";
import {
accessTokenExpirationInMinutesWithrefreshToken,
createRefreshJWTToken,
refreshTokenExpirationInDays,
refreshTokenExpirationInHours,
} from "./authenticationUtils";
import { JwtConfig, config } from "./config";
import { toHttpError } from "./http_errors";
Expand Down Expand Up @@ -252,7 +252,7 @@ export function addHttpHandler(
const now = new Date();
// time in miliseconds of refresh token expiration
const refreshTokenExpiration = new Date(
now.getTime() + 1000 * 60 * 60 * 24 * refreshTokenExpirationInDays,
now.getTime() + 1000 * 60 * 60 * refreshTokenExpirationInHours,
);
const refreshToken = createRefreshJWTToken(
{ userId: token.userId, expirationAt: refreshTokenExpiration },
Expand Down
4 changes: 2 additions & 2 deletions api/src/user_authenticateAd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { VError } from "verror";
import {
accessTokenExpirationInMinutesWithrefreshToken,
createRefreshJWTToken,
refreshTokenExpirationInDays,
refreshTokenExpirationInHours,
} from "./authenticationUtils";
import { JwtConfig, config } from "./config";
import { toHttpError } from "./http_errors";
Expand Down Expand Up @@ -247,7 +247,7 @@ export function addHttpHandler(
const now = new Date();
// time in miliseconds of refresh token expiration
const refreshTokenExpiration = new Date(
now.getTime() + 1000 * 60 * 60 * 24 * refreshTokenExpirationInDays,
now.getTime() + 1000 * 60 * 60 * refreshTokenExpirationInHours,
);
const refreshToken = createRefreshJWTToken(
{ userId: token.userId, expirationAt: refreshTokenExpiration },
Expand Down
2 changes: 2 additions & 0 deletions scripts/development/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ services:
API_DB_SCHEMA: ${API_DB_SCHEMA}
API_DB_NAME: ${API_DB_NAME}
API_REFRESH_TOKENS_TABLE: ${API_REFRESH_TOKENS_TABLE}
REFRESH_TOKEN_EXPIRATION: ${REFRESH_TOKEN_EXPIRATION}
ACCESS_TOKEN_EXPIRATION: ${ACCESS_TOKEN_EXPIRATION}
command: ["npm", "run", "watch"] # npm run watch: hot reloading
# volume to track code changes
volumes:
Expand Down
2 changes: 2 additions & 0 deletions scripts/operation/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ services:
API_DB_SCHEMA: ${API_DB_SCHEMA}
API_DB_NAME: ${API_DB_NAME}
API_REFRESH_TOKENS_TABLE: ${API_REFRESH_TOKENS_TABLE}
REFRESH_TOKEN_EXPIRATION: ${REFRESH_TOKEN_EXPIRATION}
ACCESS_TOKEN_EXPIRATION: ${ACCESS_TOKEN_EXPIRATION}
depends_on:
- alpha-node
volumes:
Expand Down

0 comments on commit 4800754

Please sign in to comment.