Skip to content

Commit 9050bde

Browse files
committed
initial oauth2-bridge implementation
0 parents  commit 9050bde

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+8878
-0
lines changed

.github/workflows/publish.yml

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Publish
2+
on:
3+
push:
4+
branches:
5+
- main
6+
tags:
7+
- "*"
8+
pull_request:
9+
branches:
10+
- main
11+
12+
env:
13+
REGISTRY: ghcr.io
14+
15+
jobs:
16+
docker:
17+
name: Docker image publishing
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v3
22+
with:
23+
fetch-depth: 0
24+
25+
- name: Setup Node.js
26+
uses: actions/setup-node@v3
27+
with:
28+
node-version: "20"
29+
30+
- name: Cache pnpm modules
31+
uses: actions/cache@v3
32+
with:
33+
path: ~/.pnpm-store
34+
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
35+
restore-keys: |
36+
${{ runner.os }}-
37+
38+
- uses: pnpm/action-setup@v2
39+
with:
40+
version: 8
41+
run_install: true
42+
43+
- name: Build
44+
run: pnpm run build
45+
46+
- name: Docker meta
47+
id: meta
48+
uses: docker/metadata-action@v4
49+
with:
50+
images: ${{ env.REGISTRY }}/${{ github.repository }}
51+
tags: |
52+
type=ref,event=tag
53+
type=ref,event=pr
54+
type=raw,value=next,enable={{is_default_branch}}
55+
56+
- name: Login to registry
57+
if: github.event_name != 'pull_request'
58+
uses: docker/login-action@v2
59+
with:
60+
registry: ${{ env.REGISTRY }}
61+
username: ${{ github.actor }}
62+
password: ${{ secrets.GITHUB_TOKEN }}
63+
64+
- name: Build and push
65+
uses: docker/build-push-action@v4
66+
with:
67+
context: .
68+
push: ${{ github.event_name != 'pull_request' }}
69+
tags: ${{ steps.meta.outputs.tags }}
70+
labels: ${{ steps.meta.outputs.labels }}

.github/workflows/tests.yml

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: Tests
2+
on:
3+
pull_request:
4+
branches:
5+
- main
6+
push:
7+
branches:
8+
- main
9+
10+
jobs:
11+
typecheck:
12+
name: Typecheck
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v3
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Setup Node.js
21+
uses: actions/setup-node@v3
22+
with:
23+
node-version: "20"
24+
25+
- name: Cache pnpm modules
26+
uses: actions/cache@v3
27+
with:
28+
path: ~/.pnpm-store
29+
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
30+
restore-keys: |
31+
${{ runner.os }}-
32+
33+
- uses: pnpm/action-setup@v2
34+
with:
35+
version: 8
36+
run_install: true
37+
38+
- name: Typecheck
39+
run: pnpm run typecheck
40+
41+
linting:
42+
name: Linting
43+
runs-on: ubuntu-latest
44+
steps:
45+
- name: Checkout
46+
uses: actions/checkout@v3
47+
with:
48+
fetch-depth: 0
49+
50+
- name: Setup Node.js
51+
uses: actions/setup-node@v3
52+
with:
53+
node-version: "20"
54+
55+
- name: Cache pnpm modules
56+
uses: actions/cache@v3
57+
with:
58+
path: ~/.pnpm-store
59+
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
60+
restore-keys: |
61+
${{ runner.os }}-
62+
63+
- uses: pnpm/action-setup@v2
64+
with:
65+
version: 8
66+
run_install: true
67+
68+
- name: Check format
69+
run: pnpm lint

.gitignore

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Nuxt dev/build outputs
2+
.output
3+
.data
4+
.nuxt
5+
.nitro
6+
.cache
7+
dist
8+
9+
# Node dependencies
10+
node_modules
11+
12+
# Logs
13+
logs
14+
*.log
15+
16+
# Misc
17+
.DS_Store
18+
.fleet
19+
.idea
20+
21+
# Local env files
22+
.env
23+
.env.*
24+
!.env.example
25+
26+
# Storage
27+
data

.vscode/settings.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
// ########## START - eslint formatting options (https://github.com/antfu/eslint-config?tab=readme-ov-file#ide-support-auto-fix-on-save) ##############
3+
// Disable the default formatter, use eslint instead
4+
"prettier.enable": false,
5+
"editor.formatOnSave": false,
6+
7+
// Auto fix
8+
"editor.codeActionsOnSave": {
9+
"source.fixAll.eslint": "explicit",
10+
"source.organizeImports": "never"
11+
},
12+
13+
// Enable eslint for all supported languages
14+
"eslint.validate": [
15+
"javascript",
16+
"javascriptreact",
17+
"typescript",
18+
"typescriptreact",
19+
"vue",
20+
"html",
21+
"markdown",
22+
"json",
23+
"jsonc",
24+
"yaml",
25+
"toml",
26+
"xml",
27+
"gql",
28+
"graphql",
29+
"astro",
30+
"svelte",
31+
"css",
32+
"less",
33+
"scss",
34+
"pcss",
35+
"postcss"
36+
],
37+
}

Dockerfile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
FROM node:20
2+
WORKDIR /app
3+
COPY .output ./
4+
CMD ["node", "server/index.mjs"]

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 GEPROG GmbH
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# OAuth2 Bridge
2+
3+
A small UI that allows to proxy oAuth2 providers that does not allow wildcard redirect uris.
4+
This is especially a problem when dealing with review environments or multi tenant environments based on subdomains.
5+
6+
## Usage
7+
8+
Use it via the docker image `ghcr.io/geprog/oauth2-bridge` with the following environment variables
9+
10+
- `NUXT_AUTH_NAME` - the session cookie name. Defaults to `oauth2-bridge-session`
11+
- `NUXT_AUTH_PASSWORD` - the master password for the admin console. Should be a random 64 characters long key.
12+
13+
The docker container exposes the entre app under port `3000`.
14+
15+
To persist data you should mount a volume `/app/data`.
16+
17+
### Managing proxies
18+
19+
In the UI you can configure different proxies.
20+
Per proxy you need to set
21+
- a `name` (must be unique)
22+
- an authorization URI e.g. `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/authorize` (with your specific tenant id of course)
23+
- a token URI e.g. `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token` (with your specific tenant id of course)
24+
25+
You can also add and remove redirect URIs per proxy.
26+
27+
To use your proxy you need to configure your app to use the following paths of the hosted oauth2-bridge
28+
- Authorization URL `/api/proxies/${proxyName}/bridge/auth`
29+
- Token URL `/api/proxies/${proxyName}/bridge/token`
30+
31+
All the "normal" oauth2 parameters like `clientId`, `clientSecrect` and so on must be define in your app.
32+
OAuth2-Bridge will forward them to the actual oAuth2 provider configured in the proxy.
33+
34+
Only requests matching one of the configured redirect URIs are allowed.
35+
36+
### Adding/Removing redirect URIs
37+
38+
Of course you can add and remove redirect URIs manually via the web app.
39+
40+
But you can also generate an API Token per Proxy.
41+
With this API Token you can add and remove redirect URIs per simple http call from your CI.
42+
43+
To add a redirect URI via curl use
44+
`curl -H "Api-Token: <PROXY_API_TOKEN>" "<OAUTH2_BRIDGE_HOST>/api/proxies/<PROXY_NAME>/redirect-uri/add?redirectUri=<REDIRECT_URI_TO_ADD>"`
45+
46+
To remove a redirect URI via curl use
47+
`curl -H "Api-Token: <PROXY_API_TOKEN>" "<OAUTH2_BRIDGE_HOST>/api/proxies/<PROXY_NAME>/redirect-uri/remove?redirectUri=<REDIRECT_URI_TO_ADD>"`

app.vue

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<template>
2+
<NuxtLayout>
3+
<NuxtPage />
4+
<UNotifications />
5+
</NuxtLayout>
6+
</template>
7+
8+
<script setup lang="ts">
9+
const toast = useToast()
10+
11+
onErrorCaptured((error) => {
12+
console.error(error)
13+
toast.add({
14+
title: 'An unexpected error occurred',
15+
description: error.message,
16+
color: 'red',
17+
})
18+
})
19+
</script>

components/LoadingAnimation.vue

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<template>
2+
<div class="flex flex-1 flex-col items-center justify-center">
3+
<UIcon
4+
name="i-heroicons-arrow-path-20-solid"
5+
class="mx-auto h-6 w-6 animate-spin text-gray-400 dark:text-gray-500"
6+
/>
7+
<p class="text-center text-sm text-gray-900 dark:text-white">
8+
Loading...
9+
</p>
10+
</div>
11+
</template>

components/PageContent.vue

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<template>
2+
<section class="flex flex-col gap-2 items-center w-full">
3+
<h2 class="font-bold text-lg">
4+
{{ title }}
5+
</h2>
6+
<slot />
7+
</section>
8+
</template>
9+
10+
<script setup lang="ts">
11+
defineProps<{ title: string }>()
12+
</script>

0 commit comments

Comments
 (0)