Skip to content

Commit 86295f8

Browse files
committed
Phase 1: Implement OAuth2/OIDC core infrastructure
Backend Implementation: - Add arctic and jsonwebtoken dependencies - Create PKCEUtils for OAuth2 PKCE flow (RFC 7636) - Create OAuth2Service for OIDC provider integration * OIDC discovery (.well-known/openid-configuration) * Authorization URL generation with PKCE * Token exchange (code for access/refresh/ID tokens) * Token refresh flow * UserInfo endpoint integration - Create OAuth2AuthorizationMiddleware (initiate auth flow) - Create OAuth2CallbackMiddleware (handle provider callback) - Create OAuth2ConnectController (/oauth2/connect endpoint) - Create OAuth2CallbackController (/oauth2/callback endpoint) Configuration: - Add OAuth2 environment variables to env_ai - Feature flag VITE_USE_OAUTH2 for gradual migration - Support for OBP-OIDC provider Features: - PKCE (Proof Key for Code Exchange) support - State parameter for CSRF protection - Session-based token storage - Comprehensive error handling - Security best practices (token expiration, flow timeout) Note: Backend infrastructure complete. Next phase: integrate with app.ts and update UserController for dual auth support.
1 parent ba783c0 commit 86295f8

File tree

9 files changed

+1458
-5
lines changed

9 files changed

+1458
-5
lines changed

env_ai

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
### OBP-API mode ###################################
2+
# If OBP-API split to two instances, eg: apis,portal
3+
# Then API_Explorer need to set two api hosts: api_hostname and this api_portal_hostname, for all Rest Apis will call api_hostname
4+
# but for all the portal home page link, we need to use this props. If do not set this, it will use api_hostname value instead.
5+
VITE_OBP_API_PORTAL_HOST=http://127.0.0.1:8080
6+
7+
8+
VITE_OBP_API_HOST=http://127.0.0.1:8080
9+
VITE_OBP_API_VERSION=v5.1.0
10+
VITE_OBP_API_MANAGER_HOST=https://apimanagersandbox.openbankproject.com
11+
VITE_OBP_API_EXPLORER_HOST=http://localhost:5173
12+
VITE_OBP_CONSUMER_KEY=0xzsimlrhdguiiuuj1ncykcxzjrogxibjff3dthl
13+
VITE_OBP_CONSUMER_SECRET=ikf5wykke1oonykb33kmx3deh5ukbdak44ieg1l5
14+
VITE_OBP_REDIRECT_URL=http://localhost:5173/api/callback
15+
VITE_OPB_SERVER_SESSION_PASSWORD=asidudhiuh33875
16+
# The above code connects to localhost on port 6379.
17+
# To connect to a different host or port, use a connection string in the format
18+
# redis[s]://[[username][:password]@][host][:port][/db-number]
19+
# Be sure to secure your Redis instance
20+
VITE_OBP_REDIS_URL = redis://127.0.0.1:6379
21+
22+
# Enable the chatbot interface "Opey"
23+
VITE_CHATBOT_ENABLED=true
24+
VITE_CHATBOT_URL=http://localhost:5000
25+
26+
# Product styling setting
27+
#VITE_OBP_LINKS_COLOR="#52b165"
28+
#VITE_OBP_HEADER_LINKS_COLOR="#39455f"
29+
#VITE_OBP_HEADER_LINKS_HOVER_COLOR="#39455f"
30+
#VITE_OBP_HEADER_LINKS_BACKGROUND_COLOR="#eef0f4"
31+
#VITE_OBP_LOGO_URL=https://static.openbankproject.com/images/obp_logo.png
32+
33+
# https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production
34+
# The value could be: development, staging, production
35+
# NODE_ENV=development
36+
37+
#DEBUG=express-session
38+
39+
### OAuth2/OIDC Configuration (New - Phase 1 Implementation) ###
40+
# Set to 'true' to use OAuth2 instead of OAuth 1.0a
41+
VITE_USE_OAUTH2=false
42+
43+
# OAuth2 Client Credentials (from OBP-OIDC)
44+
# These should match the values in OBP-OIDC/run-server.sh
45+
VITE_OBP_OAUTH2_CLIENT_ID=obp-explorer-ii-client
46+
VITE_OBP_OAUTH2_CLIENT_SECRET=CHANGE_THIS_TO_EXPLORER_SECRET_2024
47+
VITE_OBP_OAUTH2_REDIRECT_URL=http://localhost:5173/oauth2/callback
48+
49+
# OIDC Well-Known Configuration URL
50+
# For local development with OBP-OIDC:
51+
VITE_OBP_OAUTH2_WELL_KNOWN_URL=http://127.0.0.1:9000/obp-oidc/.well-known/openid-configuration
52+
53+
# Optional: Token refresh threshold (seconds before expiry)
54+
VITE_OBP_OAUTH2_TOKEN_REFRESH_THRESHOLD=300

package-lock.json

Lines changed: 55 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"@highlightjs/vue-plugin": "^2.1.0",
2626
"@types/node-fetch": "^2.6.12",
2727
"ai": "^4.1.43",
28+
"arctic": "^3.7.0",
2829
"axios": "^1.7.4",
2930
"cheerio": "^1.0.0",
3031
"class-transformer": "^0.5.1",
@@ -67,7 +68,7 @@
6768
"@testing-library/vue": "^8.1.0",
6869
"@types/jest": "^29.5.14",
6970
"@types/jsdom": "^21.1.7",
70-
"@types/jsonwebtoken": "^9.0.6",
71+
"@types/jsonwebtoken": "^9.0.10",
7172
"@types/markdown-it": "^14.1.1",
7273
"@types/node": "^20.5.7",
7374
"@types/oauth": "^0.9.6",
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Open Bank Project - API Explorer II
3+
* Copyright (C) 2023-2024, TESOBE GmbH
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*
18+
* Email: contact@tesobe.com
19+
* TESOBE GmbH
20+
* Osloerstrasse 16/17
21+
* Berlin 13359, Germany
22+
*
23+
* This product includes software developed at
24+
* TESOBE (http://www.tesobe.com/)
25+
*
26+
*/
27+
28+
import { Controller, Req, Res, Get, UseBefore } from 'routing-controllers'
29+
import { Request, Response } from 'express'
30+
import { Service } from 'typedi'
31+
import OAuth2CallbackMiddleware from '../middlewares/OAuth2CallbackMiddleware'
32+
33+
/**
34+
* OAuth2 Callback Controller
35+
*
36+
* Handles the OAuth2/OIDC callback from the identity provider.
37+
* This controller receives the authorization code and state parameter
38+
* after the user authenticates with the OIDC provider.
39+
*
40+
* The OAuth2CallbackMiddleware handles:
41+
* - State validation (CSRF protection)
42+
* - Authorization code exchange for tokens
43+
* - User info retrieval
44+
* - Session storage
45+
* - Redirect to original page
46+
*
47+
* Endpoint: GET /oauth2/callback
48+
*
49+
* Query Parameters (from OIDC provider):
50+
* - code: Authorization code to exchange for tokens
51+
* - state: State parameter for CSRF validation
52+
* - error (optional): Error code if authentication failed
53+
* - error_description (optional): Human-readable error description
54+
*
55+
* Flow:
56+
* OIDC Provider → /oauth2/callback?code=XXX&state=YYY
57+
* → OAuth2CallbackMiddleware → Original Page (with authenticated session)
58+
*
59+
* Success Flow:
60+
* 1. Validate state parameter
61+
* 2. Exchange authorization code for tokens (access, refresh, ID)
62+
* 3. Fetch user information from UserInfo endpoint
63+
* 4. Store tokens and user data in session
64+
* 5. Redirect to original page or home
65+
*
66+
* Error Flow:
67+
* 1. Parse error from query parameters
68+
* 2. Display user-friendly error page
69+
* 3. Allow user to retry authentication
70+
*
71+
* @example
72+
* // Successful callback URL from OIDC provider
73+
* http://localhost:5173/oauth2/callback?code=abc123&state=xyz789
74+
*
75+
* // Error callback URL from OIDC provider
76+
* http://localhost:5173/oauth2/callback?error=access_denied&error_description=User%20cancelled
77+
*/
78+
@Service()
79+
@Controller()
80+
@UseBefore(OAuth2CallbackMiddleware)
81+
export class OAuth2CallbackController {
82+
/**
83+
* Handle OAuth2/OIDC callback
84+
*
85+
* The actual logic is handled by OAuth2CallbackMiddleware.
86+
* This method exists only as the routing endpoint definition.
87+
*
88+
* @param {Request} request - Express request object with query params (code, state)
89+
* @param {Response} response - Express response object (redirected by middleware)
90+
* @returns {Response} Response object (handled by middleware)
91+
*/
92+
@Get('/oauth2/callback')
93+
callback(@Req() request: Request, @Res() response: Response): Response {
94+
// The middleware handles all the logic and redirects the user
95+
// This method should never actually execute
96+
return response
97+
}
98+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Open Bank Project - API Explorer II
3+
* Copyright (C) 2023-2024, TESOBE GmbH
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*
18+
* Email: contact@tesobe.com
19+
* TESOBE GmbH
20+
* Osloerstrasse 16/17
21+
* Berlin 13359, Germany
22+
*
23+
* This product includes software developed at
24+
* TESOBE (http://www.tesobe.com/)
25+
*
26+
*/
27+
28+
import { Controller, Req, Res, Get, UseBefore } from 'routing-controllers'
29+
import { Request, Response } from 'express'
30+
import { Service } from 'typedi'
31+
import OAuth2AuthorizationMiddleware from '../middlewares/OAuth2AuthorizationMiddleware'
32+
33+
/**
34+
* OAuth2 Connect Controller
35+
*
36+
* Handles the OAuth2/OIDC login initiation endpoint.
37+
* This controller triggers the OAuth2 authorization flow by delegating to
38+
* the OAuth2AuthorizationMiddleware which generates PKCE parameters and
39+
* redirects to the OIDC provider.
40+
*
41+
* Endpoint: GET /oauth2/connect
42+
*
43+
* Query Parameters:
44+
* - redirect (optional): URL to redirect to after successful authentication
45+
*
46+
* Flow:
47+
* User clicks login → /oauth2/connect → OAuth2AuthorizationMiddleware
48+
* → OIDC Provider Authorization Endpoint
49+
*
50+
* @example
51+
* // User initiates login
52+
* <a href="/oauth2/connect?redirect=/messages">Login</a>
53+
*
54+
* // JavaScript redirect
55+
* window.location.href = '/oauth2/connect?redirect=' + encodeURIComponent(window.location.pathname)
56+
*/
57+
@Service()
58+
@Controller()
59+
@UseBefore(OAuth2AuthorizationMiddleware)
60+
export class OAuth2ConnectController {
61+
/**
62+
* Initiate OAuth2/OIDC authentication flow
63+
*
64+
* The actual logic is handled by OAuth2AuthorizationMiddleware.
65+
* This method exists only as the routing endpoint definition.
66+
*
67+
* @param {Request} request - Express request object
68+
* @param {Response} response - Express response object (redirected by middleware)
69+
* @returns {Response} Response object (handled by middleware)
70+
*/
71+
@Get('/oauth2/connect')
72+
connect(@Req() request: Request, @Res() response: Response): Response {
73+
// The middleware handles all the logic and redirects the user
74+
// This method should never actually execute
75+
return response
76+
}
77+
}

0 commit comments

Comments
 (0)