feat: server stubs

This commit is contained in:
janishutz committed 2026-09-13 08:30:20 +02:00
1 parent c6ed52b40a
commit f24de723fe
11 files changed
+4804 -7

No files matched your search

View File
File renamed without changes.
+3 -3
View File
@@ -2,13 +2,13 @@
"name": "@janishutz/oidc-login-sdk-browser",
"version": "1.1.0",
"description": "SDK to communicate with and log into a backend running express-openid-connect",
"homepage": "https://github.com/janishutz/oidc-login-sdk-browser#readme",
"homepage": "https://github.com/janishutz/oidc-login-sdk#readme",
"bugs": {
"url": "https://github.com/janishutz/oidc-login-sdk-browser/issues"
"url": "https://github.com/janishutz/oidc-login-sdk/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/janishutz/oidc-login-sdk-browser.git"
"url": "git+https://github.com/janishutz/oidc-login-sdk.git"
},
"license": "GPL-3.0-or-later",
"author": "Janis Hutz",
+5
View File
@@ -0,0 +1,5 @@
# janishutz/oidc-login-sdk-server-stubs
This SDK stubs are designed to run together with my browser sdk, if you can't use the non-stub version.
## Usage
**More details to come**
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
tsc --declaration
cp ./package.json ./dist
cp ./README.md ./dist
echo "Done"
+744
View File
@@ -0,0 +1,744 @@
import eslint from '@eslint/js';
import globals from 'globals';
import stylistic from '@stylistic/eslint-plugin';
import tseslint from 'typescript-eslint';
import typescript from '@typescript-eslint/eslint-plugin';
import vue from 'eslint-plugin-vue';
const style = {
'plugins': {
'@stylistic': stylistic,
'@stylistic/js': stylistic,
'@stylistic/ts': stylistic
},
'files': [
'**/*.ts',
'**/*.js',
'**/*.mjs',
'**/*.cjs',
'**/*.tsx',
'**/*.jsx'
],
'rules': {
'sort-imports': [
'warn',
{
'ignoreCase': false,
'ignoreDeclarationSort': false,
'ignoreMemberSort': false,
'memberSyntaxSortOrder': [
'none',
'all',
'multiple',
'single'
],
'allowSeparatedGroups': false
}
],
// Formatting
'@stylistic/array-bracket-newline': [
'error',
{
'multiline': false,
'minItems': 2
}
],
'@stylistic/array-bracket-spacing': [
'error',
'always'
],
'@stylistic/array-element-newline': [
'error',
{
'consistent': false,
'multiline': false,
'minItems': 2
}
],
'@stylistic/arrow-parens': [
'error',
'as-needed'
],
'@stylistic/arrow-spacing': [
'error',
{
'before': true,
'after': true
}
],
'@stylistic/block-spacing': [
'error',
'always'
],
'@stylistic/brace-style': [
'error',
'1tbs',
{
'allowSingleLine': false
}
],
'@stylistic/comma-dangle': [
'error',
'never'
],
'@stylistic/comma-spacing': [
'error',
{
'before': false,
'after': true
}
],
'@stylistic/comma-style': [
'error',
'last'
],
'@stylistic/dot-location': [
'error',
'property'
],
'@stylistic/function-call-argument-newline': [
'error',
'consistent'
],
'@stylistic/function-call-spacing': [
'error',
'never'
],
'@stylistic/function-paren-newline': [
'error',
'multiline-arguments'
],
'@stylistic/implicit-arrow-linebreak': [
'error',
'beside'
],
'@stylistic/indent': [
'error',
4
],
'@stylistic/indent-binary-ops': [
'error',
4
],
'@stylistic/key-spacing': [
'error',
{
'beforeColon': false,
'afterColon': true
}
],
'@stylistic/keyword-spacing': [
'error',
{
'before': true,
'after': true
}
],
'@stylistic/lines-between-class-members': [
'error',
'always'
],
'@stylistic/max-len': [
'warn',
{
'code': 140,
'comments': 160,
'ignoreComments': false,
'ignoreUrls': true,
'ignoreStrings': true,
'ignoreTemplateLiterals': true,
'ignoreRegExpLiterals': true
}
],
'@stylistic/max-statements-per-line': [
'error',
{
'max': 1
}
],
'@stylistic/multiline-ternary': [
'error',
'always-multiline'
],
'@stylistic/new-parens': [
'error',
'always'
],
'@stylistic/newline-per-chained-call': 'error',
'@stylistic/no-confusing-arrow': 'error',
'@stylistic/no-extra-parens': [
'error',
'all',
{
'nestedBinaryExpressions': false,
'ternaryOperandBinaryExpressions': false,
'ignoreJSX': 'multi-line',
'nestedConditionalExpressions': false
}
],
'@stylistic/no-extra-semi': 'error',
'@stylistic/no-floating-decimal': 'error',
'@stylistic/no-mixed-operators': 'error',
'@stylistic/no-mixed-spaces-and-tabs': 'error',
'@stylistic/no-multi-spaces': 'error',
'@stylistic/no-multiple-empty-lines': [
'error',
{
'max': 3,
'maxEOF': 2
}
],
'@stylistic/no-tabs': 'error',
'@stylistic/no-trailing-spaces': 'error',
'@stylistic/no-whitespace-before-property': 'error',
'@stylistic/object-curly-newline': [
'error',
{
'multiline': true,
'minProperties': 1
}
],
'@stylistic/object-curly-spacing': [
'error',
'always'
],
'@stylistic/object-property-newline': 'error',
'@stylistic/one-var-declaration-per-line': 'error',
'@stylistic/operator-linebreak': [
'error',
'before'
],
'@stylistic/padded-blocks': [
'error',
{
'blocks': 'never',
'classes': 'always',
'switches': 'never'
}
],
// Padding lines. The most in-depth part of this config
'@stylistic/padding-line-between-statements': [
'error',
// Variables, Constants
{
'blankLine': 'never',
'prev': 'var',
'next': 'var'
},
{
'blankLine': 'never',
'prev': 'let',
'next': 'let'
},
{
'blankLine': 'never',
'prev': 'const',
'next': 'const'
},
{
'blankLine': 'always',
'prev': 'var',
'next': [
'block',
'block-like',
'break',
'cjs-export',
'cjs-import',
'class',
'const',
'continue',
'debugger',
'directive',
'do',
'empty',
'export',
'expression',
'for',
'function',
'if',
'iife',
'import',
'let',
'return',
'switch',
'throw',
'try',
'var',
'with'
]
},
{
'blankLine': 'always',
'prev': 'let',
'next': [
'block',
'block-like',
'break',
'cjs-export',
'cjs-import',
'class',
'const',
'continue',
'debugger',
'directive',
'do',
'empty',
'export',
'expression',
'for',
'function',
'if',
'iife',
'import',
'return',
'switch',
'throw',
'try',
'var',
'while',
'with'
]
},
{
'blankLine': 'always',
'prev': 'const',
'next': [
'block',
'block-like',
'break',
'cjs-export',
'cjs-import',
'class',
'continue',
'debugger',
'directive',
'do',
'empty',
'export',
'expression',
'for',
'function',
'if',
'iife',
'import',
'let',
'return',
'switch',
'throw',
'try',
'var',
'while',
'with'
]
},
// Import
{
'blankLine': 'never',
'prev': 'import',
'next': 'import'
},
{
'blankLine': 'never',
'prev': 'cjs-import',
'next': 'cjs-import'
},
{
'blankLine': 'always',
'prev': [
'block',
'block-like',
'break',
'cjs-export',
'class',
'const',
'continue',
'debugger',
'directive',
'do',
'empty',
'export',
'expression',
'for',
'function',
'if',
'iife',
'let',
'return',
'switch',
'throw',
'try',
'var',
'while',
'with'
],
'next': 'cjs-import'
},
{
'blankLine': 'always',
'prev': 'cjs-import',
'next': [
'block',
'block-like',
'break',
'cjs-export',
'class',
'const',
'continue',
'debugger',
'directive',
'do',
'empty',
'export',
'expression',
'for',
'function',
'if',
'iife',
'let',
'return',
'switch',
'throw',
'try',
'var',
'while',
'with'
]
},
{
'blankLine': 'always',
'prev': [
'block',
'block-like',
'break',
'cjs-export',
'class',
'const',
'continue',
'debugger',
'directive',
'do',
'empty',
'export',
'expression',
'for',
'function',
'if',
'iife',
'let',
'return',
'switch',
'throw',
'try',
'var',
'while',
'with'
],
'next': 'import'
},
{
'blankLine': 'always',
'prev': 'import',
'next': [
'block',
'block-like',
'break',
'cjs-export',
'class',
'const',
'continue',
'debugger',
'directive',
'do',
'empty',
'export',
'expression',
'for',
'function',
'if',
'iife',
'let',
'return',
'switch',
'throw',
'try',
'var',
'while',
'with'
]
},
// If
{
'blankLine': 'always',
'prev': '*',
'next': 'if'
},
{
'blankLine': 'always',
'prev': 'if',
'next': '*'
},
// For
{
'blankLine': 'always',
'prev': '*',
'next': 'for'
},
{
'blankLine': 'always',
'prev': 'for',
'next': '*'
},
// While
{
'blankLine': 'always',
'prev': '*',
'next': 'while'
},
{
'blankLine': 'always',
'prev': 'while',
'next': '*'
},
// Functions
{
'blankLine': 'always',
'prev': '*',
'next': 'function'
},
{
'blankLine': 'always',
'prev': 'function',
'next': '*'
},
// Block Statements
{
'blankLine': 'always',
'prev': '*',
'next': 'block-like'
},
{
'blankLine': 'always',
'prev': 'block-like',
'next': '*'
},
// Switch
{
'blankLine': 'always',
'prev': '*',
'next': 'switch'
},
{
'blankLine': 'always',
'prev': 'switch',
'next': '*'
},
// Try-Catch
{
'blankLine': 'always',
'prev': '*',
'next': 'try'
},
{
'blankLine': 'always',
'prev': 'try',
'next': '*'
},
// Throw
{
'blankLine': 'always',
'prev': '*',
'next': 'throw'
},
{
'blankLine': 'always',
'prev': 'throw',
'next': '*'
},
// Return
{
'blankLine': 'never',
'prev': 'return',
'next': '*'
},
{
'blankLine': 'always',
'prev': '*',
'next': 'return'
},
// Export
{
'blankLine': 'always',
'prev': '*',
'next': 'export'
},
{
'blankLine': 'always',
'prev': 'export',
'next': '*'
},
{
'blankLine': 'always',
'prev': '*',
'next': 'cjs-export'
},
{
'blankLine': 'always',
'prev': 'cjs-export',
'next': '*'
},
// Classes
{
'blankLine': 'always',
'prev': '*',
'next': 'class'
},
{
'blankLine': 'always',
'prev': 'class',
'next': '*'
}
],
'@stylistic/quote-props': [
'error',
'always'
],
'@stylistic/quotes': [
'error',
'single'
],
'@stylistic/rest-spread-spacing': [
'error',
'never'
],
'@stylistic/semi': [
'error',
'always'
],
'@stylistic/semi-spacing': [
'error',
{
'before': false,
'after': true
}
],
'@stylistic/semi-style': [
'error',
'last'
],
'@stylistic/space-before-blocks': [
'error',
'always'
],
'@stylistic/space-before-function-paren': [
'error',
'always'
],
'@stylistic/space-in-parens': [
'error',
'always'
],
'@stylistic/space-infix-ops': [
'error',
{
'int32Hint': false
}
],
'@stylistic/space-unary-ops': 'error',
'@stylistic/spaced-comment': [
'error',
'always'
],
'@stylistic/switch-colon-spacing': 'error',
'@stylistic/template-curly-spacing': [
'error',
'always'
],
'@stylistic/template-tag-spacing': [
'error',
'always'
],
'@stylistic/type-generic-spacing': 'error',
'@stylistic/type-named-tuple-spacing': 'error',
'@stylistic/wrap-iife': [
'error',
'inside'
],
'@stylistic/wrap-regex': 'error',
'@stylistic/ts/type-annotation-spacing': 'error'
}
};
/** @type {import('eslint').Linter.Config} */
export default tseslint.config(
// Base JavaScript rules
eslint.configs.recommended,
tseslint.configs.recommended,
style,
// Vue support (including TS and JSX inside SFCs)
{
'files': [ '**/*.vue' ],
'languageOptions': {
'sourceType': 'module',
'ecmaVersion': 'latest',
'globals': globals.browser,
'parserOptions': {
'parser': tseslint.parser
}
},
'plugins': {
'vue': vue,
'@stylistic': stylistic,
'@stylistic/js': stylistic,
'@stylistic/ts': stylistic,
'@typescript-eslint': typescript
},
'extends': [
eslint.configs.recommended,
...vue.configs['flat/recommended']
],
'rules': {
...typescript.configs.recommended.rules,
...style.rules,
// Vue specific rules
'@stylistic/indent': 'off',
'vue/html-indent': [
'error',
4
],
'vue/html-comment-indent': [
'error',
4
],
'vue/script-indent': [
'error',
4,
{
'baseIndent': 1,
'switchCase': 1
}
],
'vue/html-self-closing': [
'error',
{
'html': {
'void': 'never',
'normal': 'never',
'component': 'always'
},
'svg': 'always',
'math': 'never'
}
],
'vue/max-attributes-per-line': [
'error',
{
'singleline': 3,
'multiline': 1
}
]
}
}
);
+3942
View File
File diff suppressed because it is too large. Load diff
+33
View File
@@ -0,0 +1,33 @@
{
"name": "@janishutz/oidc-login-sdk-server-stubs",
"version": "1.1.0",
"description": "Stubs to allow for usage of services using my normal sdk to work for users that don't have an OIDC login system",
"homepage": "https://github.com/janishutz/oidc-login-sdk#readme",
"bugs": {
"url": "https://github.com/janishutz/oidc-login-sdk/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/janishutz/oidc-login-sdk.git"
},
"license": "GPL-3.0-or-later",
"author": "Janis Hutz",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@stylistic/eslint-plugin": "^5.10.0",
"eslint": "^10.10.0",
"eslint-plugin-vue": "^10.11.0",
"globals": "^17.12.0",
"typescript-eslint": "^8.70.0"
},
"dependencies": {
"@types/express": "^5.0.6",
"express": "^5.2.1",
"express-openid-connect": "^3.4.0"
}
}
+48
View File
@@ -0,0 +1,48 @@
import connect from 'express-openid-connect';
import express from 'express';
/**
* Set up the sdk. It is recommended that you use a custom SessionStore, such as RedisStore for express-session
* Furthermore, see README for required environment variables
* @param app - Express application
* @param issuer - OIDC Issuer URL
* @param appURL - URL of this application
* @param authForAllRoutes - Whether or not to require authorization on all routes
* @param scopes - Scopes to request
* @param enableBackchannelLogout - Whether or not to enable backchannel logout. If true, must provide sessionStore
* @param loginReturnURL - The URL to return to by default if none is specified as returnTo query parameter
* @param userValidation - Function to validate the user
* @param sessionStore - RECOMMENDED: Use any express-session SessionStore, like the RedisStore
* @param extraOpts - Extra configuration options, or overwrite some set here
*/
export const configure = (
app: express.Application,
_issuer: URL,
_appURL: URL,
_authForAllRoutes: boolean,
_scopes: ( 'profile' | 'email' )[],
_enableBackchannelLogout: boolean,
loginReturnURL?: URL,
_userValidation?: ( req: express.Request, res: express.Response, session: connect.Session ) => Promise<connect.Session>,
_sessionStore?: connect.SessionStore,
extraOpts?: connect.ConfigParams
) => {
app.get( '/auth/v2/check', ( _req, res ) => res.sendStatus( 200 ) );
app.get( '/auth/v2/logout', ( _req, res ) => res.redirect( '/' ) );
app.post( '/auth/v2/logout', ( _req, res ) => res.sendStatus( 200 ) );
app.get( '/auth/v2/login', ( req, res ) => {
res.redirect( req.query.returnTo ? String( req.query.returnTo ) : ( loginReturnURL?.href ?? '/' ) );
} );
console.debug( 'Extra config opts (ignored)', extraOpts );
};
export const requiresAuth = ( requiresLoginCheck?: ( req: express.Request ) => boolean ) => {
if ( requiresLoginCheck ) console.log( 'Login check will be skipped due to usage of stubs' );
return ( _req: express.Request, _res: express.Response, next: express.NextFunction ) => {
next();
};
};
+18
View File
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"allowJs": true,
"target": "ES2022",
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"types": [
"node"
],
"module": "NodeNext",
"moduleResolution": "NodeNext"
},
"include": [
"./src/**/*"
]
}
+3 -3
View File
@@ -2,13 +2,13 @@
"name": "@janishutz/oidc-login-sdk-server",
"version": "1.1.0",
"description": "Small wrapper on top of express-openid-connect to work together with my browser sdk",
"homepage": "https://github.com/janishutz/oidc-login-sdk-browser#readme",
"homepage": "https://github.com/janishutz/oidc-login-sdk#readme",
"bugs": {
"url": "https://github.com/janishutz/oidc-login-sdk-browser/issues"
"url": "https://github.com/janishutz/oidc-login-sdk/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/janishutz/oidc-login-sdk-browser.git"
"url": "git+https://github.com/janishutz/oidc-login-sdk.git"
},
"license": "GPL-3.0-or-later",
"author": "Janis Hutz",
+1 -1
View File
@@ -66,5 +66,5 @@ export const configure = (
} );
};
/** Re-Export of express-openid-connect's requiresAuth function */
/** Re-Export of express-openid-connect's requiresAuth function, this should be used instead of directly if you also want to use the stubs */
export const requiresAuth = connect.requiresAuth;